移动部分值后丢弃已移动值相关编译错误咨询:期望代码输出Foo(6)
为什么你的Rust代码会触发借用冲突?
这个问题我之前碰到过好多次,核心原因在于Rust的借用检查器是基于词法作用域来判断借用生命周期的——哪怕你觉得变量已经没用了,只要它的词法作用域没结束,借用就不算释放。
咱们来拆解你的错误:
- 当你写
let b = get_foo(&mut a);时,对a的可变借用就创建了,这个借用的作用域是从这一行开始,一直到整个函数结束(也就是最后的})。 - 你可能以为match块之后
b就被丢弃了,借用也该跟着释放,但借用检查器不会追踪变量的实际使用时机——它只认代码的词法范围。所以后面println!("{:?}", a)尝试读取a时,就会和还在生效的可变借用冲突,直接报错。
哪怕你手动调用drop(b)也没用,因为借用的生命周期和变量的词法作用域绑定,不是变量被销毁就立刻释放借用的。
怎么解决?缩小可变借用的作用域
最简单的办法就是给可变借用的代码套个大括号,手动缩小它的词法作用域,让借用检查器明确知道“这个可变借用在这里就结束了”。
比如改成这样:
fn main() { let mut a = Foo(0); // 用大括号把可变借用的代码包起来 { let b = get_foo(&mut a); // 这里放你的match逻辑 match b { Foo(val) => println!("b的值是Foo({})", val), } // 大括号结束,可变借用自动释放 } // 现在可变借用已经失效,安全打印a println!("{:?}", a); } #[derive(Debug)] struct Foo(i32); fn get_foo(a: &mut Foo) -> Foo { a.0 = 6; Foo(a.0) }
这样修改后,可变借用的作用域被限制在大括号内部,当程序走到println时,可变借用已经完全释放,就不会再触发冲突了。
如果你的get_foo返回的是&mut Foo类型的引用,这个方法同样适用——只要把持有引用的变量放在独立的作用域里,就能让借用提前结束。
内容的提问来源于stack exchange,提问作者Ákos Vandra-Meyer
相关产品推荐
相关产品推荐

