You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:47:46