簡體   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