基于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 回答
重要的不是匹配值的类型,而是每个匹配臂上绑定的每个值的类型 .
在结构
Point
中,字段x
和y
的类型为i32
. 此类型实现Copy
,因此Rust将复制此类型的值而不是移动它们 - 这意味着原始值仍被视为有效 . 由于匹配臂上绑定的所有值都实现Copy
,因此无需使origin
无效 . 字段访问的工作方式类似:origin.x
在origin.x
实现Copy
时不会使origin
无效!现在,如果字段的类型没有实现
Copy
(例如,String
),那么这是一个不同的故事 . Rust被迫将每个String
从字段移动到匹配臂中的绑定 . 因此,origin
中的字段无效 . 由于我们不能将值与无效字段一起使用,因此整个结构也会失效 .让我们稍微调整一下 . 请考虑以下代码:
在这里,我们使用占位符模式(
_
)来表示我们对某个字段的值不感兴趣 . 我们也可以使用通配符模式(..
,如Point { x: x1, .. }
)来忽略结构模式中未命名的所有字段 . 在任何一种情况下,它都具有 not moving the ignored field(s) 的效果 .在前两个匹配中,我们仅绑定
x
字段,其类型为i32
. 由于i32
实现Copy
,origin
未被无效,即使origin
和origin.y
都不可复制(origin.y
只是保持原样) .在第三个匹配中,我们只绑定
y
字段,其类型为String
. 由于String
未实现Copy
,origin.y
被移入y1
,因此origin
无效 . 这会在第四次匹配时导致编译器错误,因为它在失效后尝试使用origin
: