了解枚举 Rust 的移动语义



所以我正在查看 impl foris_some()forOption,我注意到它在引擎盖下使用了match *self {}......所以它在内部移动它。

我的问题是,如果它被移动了,我怎么能做这样的事情?https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f094da12290b77bad526674467e51043

fn main() {
let x = Option::Some(3);
x.is_some();
x.is_some();
}

我的期望是我应该只能调用is_some()一次,下次我调用它时,我应该会收到某种错误,说它已被移动......但是不,这一切都编译得很好。

我误解了什么?

match *self { ... }中的*self不会移动(或复制(self指向的内容。来自"The Rust Reference"(强调我的(,

match的行为会有所不同,具体取决于仔细检查表达式是位置表达式还是值表达式。如果仔细表达式是值表达式,则首先将其计算到临时位置,...

当 scrutinee 表达式是 place 表达式时,匹配项不会分配临时位置;但是,按值绑定可能会从内存位置复制或移动。

*self是一个地方表达式。来自"The Rust Reference"(强调我的(,

表达式

分为两大类:位置表达式和值表达式。

位置表达式是表示内存位置的表达式这些表达式是引用局部变量、静态变量、取消引用 (*expr(、数组索引表达式 (expr[expr](、字段引用 (expr.f( 和括号中的 place 表达式的路径。所有其他表达式都是值表达式。

值表达式是表示实际值的表达式


您可能还有兴趣知道match体内的Some(_) => true臂不会束缚任何东西。来自"锈参考",

与标识符模式不同,它不会复制、移动或借用它匹配的值。

其中"it"表示通配符模式(_(。

(有关更官方和引用的答案,请参阅@dkim的答案(

如果函数的签名通过引用接受,则它不会获得值的所有权。Option.is_some(( 实际上采取 &self 而不是自我。

有趣的部分是如何允许在函数中使用*self,该函数在Self: Copy不受限制时接收&self

为了测试这一点,让我们创建一个包含类似内容的最小示例:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d7b137b74b5cd8f8bb57398ae01bf4e3

#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_) => {
//  dbg!(s);
}
A::Y(_i) => {
//  dbg!(i);
}
};
}

这编译得很好。但是,让我们将A::X(_)模式更改为A::X(_s):https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=93030e5c3f84532532c5db966c798bd6

#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_s) => {
//  dbg!(s);
}
A::Y(_i) => {
//  dbg!(i);
}
};
}

这无法编译:

error[E0507]: cannot move out of `a.0` which is behind a shared reference
--> src/lib.rs:7:11
|
7 |     match *a {
|           ^^ help: consider borrowing here: `&*a`
8 |         A::X(_s) => {
|              --
|              |
|              data moved here
|              move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait

因此,取消引用非复制枚举似乎是完全可以的,只要它不用于移动内部非复制值。_很好,因为它保证永远不会使用基础值,而_s不会编译,因为它只是一个普通的 allow(未使用(变量。

这也是有道理的,因为它允许相同的匹配臂同时适用于复制和非复制类型,只要没有使用违反所有权规则

最新更新