如何解决Rust中的'already mutably borrowed: BorrowError'错误?
解决Rust中RefCell的
already mutably borrowed: BorrowError错误 问题背景
我对Rust的RefCell不太熟悉,遇到了以下运行时panic错误,希望得到解决方法:
错误信息
thread 'main' panicked at 'already mutably borrowed: BorrowError', src/main.rs:47:22
相关代码
use std::{ cell::RefCell, rc::{Rc, Weak}, }; // parent struct P { i: Rc<RefCell<I>>, } impl P { fn new() -> P { let b = B { v: "b".to_string(), i: Weak::new(), }; let c = C { v: "c".to_string(), i: Weak::new(), }; let i = Rc::new(RefCell::new(I { b, c })); let ii = i.clone(); let p = P { i }; // init b.i let mut borrow_mut = RefCell::borrow_mut(&ii); let bb = &mut borrow_mut.b; bb.i = Rc::downgrade(&ii); // init c.i let cc = &mut borrow_mut.c; cc.i = Rc::downgrade(&ii); p } fn update_bv_cv(&self) { // update b.v let mut borrow_mut = RefCell::borrow_mut(&self.i); let b = &mut borrow_mut.b; b.v.push_str("=>p.update_bv_cv"); // update c.v let c = &mut borrow_mut.c; c.v.push_str("=>p.update_bv_cv"); // b update c.v let borrow = RefCell::borrow(&self.i); let b = &borrow.b; b.update_cv(); } fn get_bv_cv(&self) -> (String, String) { let i = &self.i; let ii = i.borrow(); let bv = ii.b.v.as_str(); let cv = ii.c.v.as_str(); (bv.into(), cv.into()) } } // parent inner struct I { c: C, b: B, } // child struct C { i: Weak<RefCell<I>>, v: String, } // child struct B { i: Weak<RefCell<I>>, v: String, } impl B { fn update_cv(&self) { if let Some(i) = self.i.upgrade() { let mut ii = RefCell::borrow_mut(&i); ii.c.v.push_str("b.udpate_cv"); } } } fn main() { let p = P::new(); p.update_bv_cv(); let (bv, cv) = p.get_bv_cv(); println!("b.v: {bv}\nc.v: {cv}"); }
错误原因分析
错误触发在update_bv_cv方法中,核心问题是RefCell的借用规则被违反:
- 首先调用
RefCell::borrow_mut(&self.i)获取了self.i的可变借用,这个借用会一直持续到borrow_mut变量离开作用域。 - 后续尝试调用
RefCell::borrow(&self.i)获取不可变借用,而RefCell的规则是:只要有活跃的可变借用,就不允许创建任何新的借用(可变或不可变),因此直接触发运行时panic。 - 即使这一步的不可变借用成功,
b.update_cv()内部又会尝试获取i的可变借用,同样会因为已有活跃可变借用而panic。
解决方案
核心思路是缩小借用的作用域,确保在获取新借用前释放之前的借用。修改update_bv_cv方法如下:
fn update_bv_cv(&self) { // 用代码块限制可变借用的作用域 { let mut borrow_mut = self.i.borrow_mut(); borrow_mut.b.v.push_str("=>p.update_bv_cv"); borrow_mut.c.v.push_str("=>p.update_bv_cv"); } // 此处borrow_mut离开作用域,可变借用被自动释放 // 现在可以安全地获取不可变借用并调用方法 self.i.borrow().b.update_cv(); }
修改说明
- 通过大括号
{}将更新b.v和c.v的代码包裹,让可变借用borrow_mut的生命周期仅限于这个代码块,执行完后立即释放。 - 后续获取不可变借用并调用
update_cv时,没有活跃的可变借用,因此update_cv内部的可变借用也能正常获取,不会触发panic。
运行结果
修改后代码运行会输出:
b.v: b=>p.update_bv_cv c.v: c=>p.update_bv_cvb.udpate_cv
内容的提问来源于stack exchange,提问作者lost.sof
相关产品推荐
相关产品推荐

