gpt4 book ai didi

rust - 如何在不复制内容的情况下对实现 Deref 的类型(例如 Box)中的值进行模式匹配?

转载 作者:行者123 更新时间:2023-11-29 08:13:50 25 4
gpt4 key购买 nike

我的数据包含在 Box 中,我想对其进行模式匹配而不意外地将 Box 的内容从堆复制到堆栈;我该怎么做?

让我们假设以下代码:

enum SomeEnum {
SomeEntry,
AnotherEntry,
}

fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);

match *boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}

这是将开箱即用的枚举复制到堆栈上并对该副本进行模式匹配,还是直接对盒子指向的值进行匹配?

这个变体怎么样?

use std::ops::Deref;

enum SomeEnum {
SomeEntry,
AnotherEntry,
}

fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);

match boxed_value.deref() {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}

似乎简单地取消引用一个框并不会自动创建一个副本,否则将无法使用 let x = &*boxed_value 创建对包含值的引用。这导致了有关此语法的问题:

enum SomeEnum {
SomeEntry,
AnotherEntry,
}

fn main() {
let boxed_value = Box::new(SomeEnum::AnotherEntry);

match &*boxed_value {
SomeEnum::SomeEntry => {}
SomeEnum::AnotherEntry => {}
}
}

最佳答案

首先:在 Rust 中,没有隐含的高成本副本,这与 C++ 不同。而在 C++ 中,默认操作是“深度复制”(通过复制构造函数或类似方法),而 Rust 中的默认操作是移动。移动是一个浅拷贝,(a) 通常非常小且便宜,(b) 在大多数情况下可以被优化器删除。要在 Rust 中获得深度克隆,您必须手动使用 .clone()。如果您不这样做,您通常不必为此担心

第二:对枚举的匹配仅查看该枚举的判别式(除非您绑定(bind)枚举字段,请参见下文)。那是指定枚举的哪个变体存储在值中的“标签”或“元数据”。该标签很小:几乎在所有情况下它都适合 8 位(具有超过 256 个变体的枚举很少见)。所以你不必为此担心。在您的情况下,我们有一个没有任何字段的类似 C 的枚举。所以枚举只存储标签,因此也很小。

那么复制可能代价高昂的枚举字段呢?像这样:

enum SomeEnum {
SomeEntry(String),
AnotherEntry,
}

let boxed_value = Box::new(SomeEnum::AnotherEntry);

match *boxed_value {
SomeEnum::SomeEntry(s) => drop::<String>(s), // make sure we own the string
SomeEnum::AnotherEntry => {},
}

所以在这种情况下,一个变体存储一个 String。由于深度复制一个字符串的成本有点高,Rust 不会隐式地这样做。在匹配臂中,我们尝试删除 s 并断言它是一个 String。这意味着我们(意思是:火柴臂的主体)拥有绳子。因此,如果 match arm 拥有它但我们没有从克隆它中获得拥有的值,这意味着外部函数不再拥有它。事实上,如果您尝试在匹配后使用 boxed_value,您将会从编译器中得到移动错误。同样,要么出现编译器错误,要么没有坏事自动发生。

此外,您可以在匹配中编写SomeEnum::SomeEntry(ref s)。在这种情况下,字符串通过引用绑定(bind)到 s(因此 drop() 调用将不再起作用)。在那种情况下,我们永远不会从 boxed_value 移动。这就是我所说的“延迟搬家”,但我不确定这是否是一个官方术语。但这只是意味着:当模式匹配时,输入值根本不会移动,直到模式中的绑定(bind)从它移动。

最后请看this code and the generated assembly .装配是最佳的。所以再说一遍:当您来自 C++ 世界时,您可能会担心意外克隆,但在 Rust 中这并不是您真正需要担心的事情。

关于rust - 如何在不复制内容的情况下对实现 Deref 的类型(例如 Box)中的值进行模式匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53132035/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com