基于 Preventing move semantics during pattern matching ,我的理解是,当我对结构执行 match
时,如果不使用引用来进行匹配,则该结构将被 move ,因为它不是原始类型。为了对此进行测试,我实现了以下内容:
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)
,这意味着原始结构仍然存在。它不应该在第一次 匹配
之后 move 吗?
最佳答案
重要的不是匹配值的类型,而是每个匹配臂上绑定(bind)的每个值的类型。
在您的结构 Point
中,字段 x
和 y
的类型为 i32
。这个类型实现了Copy
,所以 Rust 会复制这个类型的值而不是 move 它们——这意味着原始值仍然被认为是有效的。由于匹配臂上绑定(bind)的所有值都实现了 Copy
,因此没有必要使 origin
无效。字段访问的工作方式类似:当 origin.x
实现 Copy
时,origin.x
不会使 origin
无效!
现在,如果字段的类型没有实现Copy
(例如,String
),那就另当别论了。 Rust 被迫将每个 String
从字段 move 到匹配臂中的绑定(bind)。结果,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, .. }
)来忽略所有未在结构模式中命名的字段.在任何一种情况下,它都具有不 move 被忽略的字段的效果。
在前两次匹配中,我们只绑定(bind)了x
字段,它的类型是i32
。由于 i32
实现了 Copy
,因此 origin
不会失效,即使 origin
和 origin.y
是可复制的(origin.y
只是停留在原处)。
在第三个匹配中,我们只绑定(bind)y
字段,它是String
类型。由于 String
没有实现 Copy
,origin.y
被 move 到 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
关于pattern-matching - 为什么这个结构在模式匹配后没有 move ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40353047/