繁体   English   中英

了解枚举Rust的移动语义

[英]Understanding move semantics for enums Rust

所以我在看Option is_some() ,我注意到它在is_some()使用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() ,而下次调用它时,我应该会收到一些错误消息,说它已经被移动了……但是,所有的编译都很好。

我有什么误会?

*self in match *self { ... }不会移动(或复制) self指向的内容。 从“ The Rust Reference ”(重点是我的),

match行为取决于scrutinee表达式是place表达式还是value表达式。 如果scrutinee表达式是一个值表达式,则首先将其求值到一个临时位置, ...

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

*self是一个地方表达。 从“ The Rust Reference ”(重点是我的),

表达式分为两个主要类别:位置表达式和值表达式。 ...

位置表达式是代表存储位置的表达式。 这些表达式是引用局部变量,静态变量, 取消引用( *expr ,数组索引表达式( expr[expr] ),字段引用( expr.f )和带括号的位置表达式的expr.f 所有其他表达式都是值表达式。

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


您可能还想知道match正文中的Some(_) => true手臂没有任何约束。 从“ The Rust Reference ”中,

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

其中“ it”表示通配符模式( _ )。

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

如果函数的签名通过引用接受,则它不拥有该值的所有权。 Option.is_some()实际上需要&self而不是self。

有趣的部分是当Self: Copy不受限制时,如何允许*self在接收&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 : A::X(_s) ? A::X(_s) = A::X(_s) & A::X(_s) = A::X(_s) & A::X(_s) = A::X(_s) & A::X(_s) = A::X(_s)

#[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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM