为什么这个结构在模式匹配后没有移动?

Why is this struct not moved after 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 之后移动吗?

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

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

时,origin.x 不会使 origin 无效

现在,如果字段的类型未实现 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 实现了 Copy,因此 origin 没有失效,即使 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