使用if let触发already borrowed恐慌的原因及两种写法差异
问题解答
1. 两种写法的核心差异
两种写法的本质区别是**x.borrow()返回的Ref实例的作用域不同**:
- 第一种写法里,
x.borrow()是if let条件表达式的一部分,Rust会自动延长这个临时Ref对象的生命周期,让它覆盖整个if let的代码块(包括执行x.borrow_mut().bar();的阶段)。 - 第二种写法里,
x.borrow()仅用来调用foo()获取Option<u32>,赋值给foo变量后,Ref实例就立刻被销毁了——因为foo存的是foo()返回的数值,不是Ref本身,所以不可变借用提前释放了。
2. 第一种写法触发恐慌的原因
第一种写法确实产生了持续的不可变借用,直接违反了RefCell的运行时借用检查规则:
当执行x.borrow()时,RefCell会记录当前存在一个活跃的不可变借用;而在if let代码块里调用x.borrow_mut()时,RefCell检测到此时已有未释放的不可变借用,同一时间不能同时存在不可变和可变借用,所以触发already borrowed!的运行时恐慌。
示例代码回顾
fn main() { struct Test; impl Test{ fn foo(&self) -> Option<u32>{ Some(0) } fn bar(&mut self){ println!("bar") } } let x = Rc::new(RefCell::new(Test{})); // Runtime panic: already borrowed! if let Some(foo) = x.borrow().foo(){ x.borrow_mut().bar(); } // Run perfectly! let foo = x.borrow().foo(); if let Some(foo) = foo{ x.borrow_mut().bar(); } () }
内容的提问来源于stack exchange,提问作者Preston
相关产品推荐
相关产品推荐

