为什么Rust编译器报partial move错误而非完全移动错误?
Rust部分移动问题解答
为什么报错是部分移动而非普通完全移动?
x的类型是Option<&mut i32>,属于enum复合类型。Rust的所有权规则中,部分移动是专门针对复合类型的场景:当你仅解构取出复合类型的某一个/几个成员的所有权时,只会移动被取出的成员,而非整个值,这种情况就被定义为部分移动。
如果直接执行let new_x = x;才会触发x的完全移动,但你代码中是通过match解构x,仅取出了Some变体中存储的&mut i32值绑定到z,外层的Option结构本身并没有被移走,只是它内部的一个字段被移走了,所以编译器判定为部分移动。
从x到z的部分移动发生过程
- 执行
let x = Some(&mut y);时,构造了一个Option枚举,内部持有y的可变引用,整个Option的所有权归x所有。 - match匹配
x进入Some(z)分支时,该模式会直接解构Option,把内部的&mut i32值的所有权转移给z,此时x的Some变体内部的字段已经为空,x变成了部分被移动的不完整值。 - 后续
println!("{:?}",x)需要访问完整的x,就会触发所有权错误。
&mut T没有实现Copy trait,为什么没有触发完全移动?
这个误解的核心是混淆了「移动的规则」和「移动的范围」:&mut T没有实现Copy trait只会导致它被使用的时候必然发生移动,不会改变移动的范围——你通过模式匹配要拿的是作为Option内部成员的&mut T本身,自然只会移动它自己,不会连带把外层的整个Option都移走。
编译器报错中文翻译
正在编译 playground v0.0.1 (/playground) error[E0382]: 借用了已被部分移动的值: `x` --> src/main.rs:10:21 | 6 | Some(z) => { | - 此处发生值的部分移动 ... 10 | println!("{:?}",x); | ^ 此处在部分移动后借用了值 | = note: 发生部分移动的原因是对应值的类型为`&mut i32`,该类型没有实现`Copy` trait 帮助: 在模式中借用该字段即可避免移动`x.0` | 6 | Some(ref z) => { | ^^^ 如需了解该错误的更多信息,请执行`rustc --explain E0382` error: 因之前的错误,无法编译`playground`项目
修复方案
按照编译器提示,在模式匹配时加ref关键字,改为Some(ref z),此时是借用Option内部的&mut i32而不是拿走所有权,不会触发移动,后续x可以正常使用。
内容的提问来源于stack exchange,提问作者bornfree
相关产品推荐
相关产品推荐

