Rust可变/不可变借用冲突:两种写法为何编译结果不同?
Rust生命周期借用冲突问题解析
问题复现代码
编译失败的写法
struct Bar<'a> { foo: &'a Foo, } struct Foo; impl Foo { fn borrow_mut(&mut self) { unimplemented!() } fn create_option_bar(&self) -> Option<Bar> { unimplemented!() } fn create_bar(&mut self) -> Bar { let option_bar = self.create_option_bar(); if option_bar.is_some() { return option_bar.unwrap(); } self.borrow_mut(); unimplemented!() } }
编译成功的写法
fn can_guarantee_option_bar_will_be_some() -> bool { unimplemented!() } struct Bar<'a> { foo: &'a Foo, } struct Foo; impl Foo { fn borrow_mut(&mut self) { unimplemented!() } fn create_option_bar(&self) -> Option<Bar> { unimplemented!() } fn create_bar(&mut self) -> Bar { if can_guarantee_option_bar_will_be_some() { return self.create_option_bar().unwrap(); } self.borrow_mut(); unimplemented!() } }
编译失败的错误信息
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable --> src/main.rs:44:9 | 37 | fn create_bar(&mut self) -> Bar { | - let's call the lifetime of this reference `'1` ... 41 | if let Some(bar) = self.create_option_bar() { | ------------------------ immutable borrow occurs here 42 | return bar; | --- returning this value requires that `*self` is borrowed for `'1` 43 | } 44 | self.borrow_mut(); | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
原因分析
第一种写法编译失败的原因
在create_bar函数中:
- 调用
self.create_option_bar()时,会对self产生不可变借用,这个借用的生命周期需要和返回的Bar结构体中foo字段的引用生命周期绑定。 - 变量
option_bar持有这个不可变借用的产物,编译器会认为这个借用的生命周期覆盖了option_bar存在的整个范围——也就是从定义到函数结束(编译器无法提前确定if分支后option_bar是否会被使用)。 - 当后续执行
self.borrow_mut()时,self仍处于不可变借用的状态,违反了Rust的核心借用规则:同一时间不能同时存在可变借用和不可变借用,因此触发E0502错误。
第二种写法编译成功的原因
修改后的代码将判断逻辑与create_option_bar()的调用分离:
- 如果
can_guarantee_option_bar_will_be_some()返回true,函数会直接调用self.create_option_bar().unwrap()并返回,后续的self.borrow_mut()不会执行——此时不可变借用的生命周期仅到返回值,不会影响后续代码。 - 如果进入
else分支,self.create_option_bar()根本没有被调用,不存在对self的不可变借用,因此self.borrow_mut()的可变借用完全合法。
编译器能清晰分析出两种分支下,不可变借用和可变借用不会同时存在,因此允许编译通过。
内容的提问来源于stack exchange,提问作者doliphin
相关产品推荐
相关产品推荐

