显式生命周期注解为何会触发双重可变借用错误?
为何显式生命周期注解会触发双重可变借用错误?
问题重现
给定示例代码:
fn main() { let v = 0u64; let mut a = A { x: "hello".to_string(), y: &v, }; a.hello(); a.world(); // 这里触发双重可变借用错误 } struct A<'a> { x: String, y: &'a u64, } impl<'a> A<'a> { fn hello(&'a mut self) { self.world(); self.x = "hello123".to_string(); let _ = *self.y; self.world(); } fn world(&mut self) { self.x = "world".to_string(); } }
编译时会出现以下错误:
| 9 | a.hello(); | --------- first mutable borrow occurs here 10 | a.world(); | ^^^^^^^^^ | | | second mutable borrow occurs here | first borrow later used here
但如果将A::hello的签名修改为fn hello(&mut self)(移除显式'a注解),程序就能正常编译运行。
原因分析
1. 显式生命周期注解的绑定效果
结构体A<'a>的生命周期参数'a是用来约束字段y的引用生命周期的——y的引用必须存活至少'a时长,而这里y引用了main里的v,所以'a的生命周期等同于v的生命周期(即整个main函数的执行周期)。
当给hello函数的&mut self标注'a时,相当于强制这个可变借用的生命周期和结构体的'a生命周期绑定。也就是说,调用a.hello()后,a的可变借用会一直持续到'a结束(也就是main函数结束)。
在这种情况下,后续调用a.world()时,尝试再次对a进行可变借用,就会和之前未释放的可变借用冲突,触发双重可变借用错误。
2. 隐式生命周期推导的行为
当去掉hello函数的显式生命周期注解,写成fn hello(&mut self)时,Rust会自动推导这个可变借用的生命周期:它的生命周期是临时的,仅在hello函数的执行期间有效。当hello函数执行完毕后,这个可变借用就会被释放,此时再调用a.world()就可以正常获取新的可变借用,不会产生冲突。
补充:函数内部的借用为何没问题?
在hello函数内部两次调用world,虽然world也需要&mut self,但这些借用都是嵌套在hello的可变借用内部的。Rust的借用检查器允许这种嵌套的可变借用,因为它们的生命周期都被包含在hello函数的借用生命周期内,不会产生跨函数的借用冲突。
内容的提问来源于stack exchange,提问作者sammyne
相关产品推荐
相关产品推荐

