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

时间:2016-11-01 01:45:22

标签: pattern-matching rust move

基于Preventing move semantics during pattern matching,我的理解是当我对结构执行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),
}

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

1 个答案:

答案 0 :(得分:5)

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

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

现在,如果字段属于未实现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),
}

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

在前两个匹配项中,我们只绑定x字段,类型为i32。由于i32实现Copyorigin不会失效,即使originorigin.y都不可复制(origin.y只是保持原样)

在第三场比赛中,我们只绑定y字段,其类型为String。由于String未实现Copyorigin.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