不匹配的 arm 是否在 Rust 的 "match" 语句中获取变量的所有者?

Does non-matching arm take the owner of a variable in a "match" statement in Rust?

我是 Rust 新手。下面是我的测试。

#[derive(Debug)]
enum Food {
    Cake,
    Pizza,
    Salad,
}

#[derive(Debug)]
struct Bag {
    food: Food
}

fn main() {
    let bag = Bag { food: Food::Cake };
    match bag.food {
        Food::Cake => println!("I got cake"),
        x => println!("I got {:?}", x)
    }

    println!("{:?}", bag);
}

当我 运行 它时,我得到了一个错误。

error[E0382]: borrow of moved value: `bag`
  --> src\main.rs:20:22
   |
17 |         x => println!("I got {:?}", x)
   |         - value moved here
...
20 |     println!("{:?}", bag);
   |                      ^^^ value borrowed here after partial move
   |
   = note: move occurs because `bag.food` has type `Food`, which does not implement the `Copy` trait

很明显 bag.food 不会匹配代码中的 x arm。为什么移动发生在那里?

x 分支在运行时不被采用并不重要,因为 match 是否取得其参数的所有权并不取决于 match 的哪个分支将实际上被采取。很像这段代码(另见 ):

let foo = "blargh".to_owned();
if false {
    let _bar = foo;
}
println!("{}", foo); // error[E0382]: borrow of moved value: `foo`

foo 从未实际移动过,但这对它在 if 之后是否有效没有任何影响(它不是)。

问题中的 match 取得了 bag.food 的所有权(使 bag 无效),因为它有一个取得所有权的分支。如果您不希望该特定分支获得所有权,您可以使用 ref 模式来借用:

match bag.food {
    Food::Cake => println!("I got cake"),
    ref x => println!("I got {:?}", x)
}

或者,自 Rust 1.26 以来,编译器知道如何将值模式(例如 Food::Cake)绑定到引用(例如 &bag.food),因此您可以编写:

match &bag.food {
    Food::Cake => println!("I got cake"),
    x => println!("I got {:?}", x)
}

在本例中,Food::Cake 匹配值,但 x 匹配并绑定到引用,因此它与前面带有 ref 的代码片段执行相同的操作。 (您可能会看到它被称为 "default binding modes" 或 "match ergonomics"。)