为什么这个结构在模式匹配后没有移动?
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
中,字段 x
和 y
的类型为 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
没有失效,即使 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
基于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
中,字段 x
和 y
的类型为 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
没有失效,即使 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