基于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
之后移动吗?
答案 0 :(得分:5)
重要的不是匹配值的类型,而是每个匹配臂上绑定的每个值的类型。
在您的结构Point
中,字段x
和y
的类型为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
实现Copy
,origin
不会失效,即使origin
和origin.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