为什么在模式匹配后不会移动此结构?

ena*_*naJ 2 move pattern-matching rust

基于在模式匹配期间防止移动语义,我的理解是当我match对结构进行操作时,如果不使用引用来进行匹配,则结构将被移动,因为它不是基本类型.为了测试这个,我实现了以下内容:

struct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
}

// to check if the origin has been moved, and it seems not, why ?? 
match origin {
    Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
}
Run Code Online (Sandbox Code Playgroud)

输出是(0,0) (0,0),这意味着原始结构仍然存在.它不应该在第一次之后被移动match吗?

Fra*_*gné 5

重要的不是匹配值的类型,而是每个匹配臂上绑定的每个值的类型.

在您的结构中Point,字段xy类型i32.此类型实现Copy,因此Rust将复制此类型的值而不是移动它们 - 这意味着原始值仍被视为有效.由于匹配臂上绑定的所有值都实现Copy,因此不必使其无效origin.字段访问的工作方式类似:在实现时origin.x不会失效!originorigin.xCopy

现在,如果字段是一种没有实现的类型Copy(例如String),那么这是一个不同的故事.Rust被迫String从场中移动到匹配臂中的绑定.结果,字段origin无效.由于我们不能将值与无效字段一起使用,因此整个结构也会失效.

让我们稍微调整一下.请考虑以下代码:

struct Point {
    x: i32,
    y: String,
}

let origin = Point { x: 0, y: "zero".to_string() };

match origin {
    Point { x: x1, y: _ } => println!("({},...)", x1),
}

match origin {
    Point { x: x1, y: _ } => println!("({},...)", x1),
}

match origin {
    Point { x: _, y: y1 } => println!("(...,{})", y1),
}

match origin {
    Point { x: _, y: y1 } => println!("(...,{})", y1),
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用占位符模式(_)来表示我们对某个字段的值不感兴趣.我们还可以使用通配符模式(..如在Point { x: x1, .. })中忽略结构模式中未命名的所有字段.在任何一种情况下,它都具有不移动被忽略的字段的效果.

在前两个匹配中,我们只绑定x字段,它是类型i32.因为i32实现Copy,origin不会失效,即使它们都不originorigin.y可复制的(origin.y只是停留在它的位置).

在第三个匹配中,我们只绑定类型的y字段String.由于String未实现Copy,origin.y被移入y1,因此origin无效.这会在第四次匹配时导致编译器错误,因为它origin在失效后尝试使用:

error[E0382]: use of partially moved value: `origin`
  --> <anon>:21:11
   |
18 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
   |                          -- value moved here
...
21 |     match origin {
   |           ^^^^^^ value used here after move
   |
   = note: move occurs because `origin.y` has type `std::string::String`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `origin.y`
  --> <anon>:22:26
   |
18 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
   |                          -- value moved here
...
22 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
   |                          ^^ value used here after move
   |
   = note: move occurs because `origin.y` has type `std::string::String`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)