Rust 内联调用RefCell的borrow_mut触发BorrowMutError如何解决?
报错根因
RefCell<T> 是通过运行时动态检查来执行借用规则的,违反以下任意一条就会触发 BorrowMutError:
- 同一时刻不允许多个可变借用共存
- 同一时刻不允许不可变借用和可变借用共存
就算你把链式调用的第一个borrow_mut()改成borrow(),报的错还是一模一样,本质是没找对真正的借用冲突点:你写的链式表达式里,前序生成的临时借用守卫,存活周期会覆盖后续的可变借用操作,而且两次借用刚好指向了同一个RefCell实例。
常见踩坑场景
- 自引用导致的同实例借用冲突
你之前修改的这行代码:
这行代码执行的时候,首先会对// 最初的写法 x.borrow_mut().parent.as_ref().unwrap().borrow_mut().left = ...; // 调整第一个borrow的类型后 x.borrow().parent.as_ref().unwrap().borrow_mut().left = ...;x指向的RefCell创建临时借用守卫:- 如果调用的是
borrow_mut(),会持有x的可变借用,直到整个表达式跑完才会释放 - 如果调用的是
borrow(),会持有x的不可变借用,直到整个表达式跑完才会释放
等后续取parent节点调用borrow_mut()的时候,如果parent字段存的Tree(也就是Rc<RefCell<TreeNode>>)和x本身是同一个实例——比如构造测试数据的时候不小心把parent指针写错了,让x.parent直接指向了x自己——就会出现对同一个RefCell的交叉借用:你手里还攥着x的不可变/可变借用,转头就对同一个节点申请可变借用,直接触发运行时恐慌。
- 如果调用的是
- 未及时释放的借用守卫引发冲突
写连续的树操作时,如果把borrow/borrow_mut()返回的守卫存成长期变量,没有在修改节点前主动释放,也会引发冲突。只要守卫还在作用域里,后续对对应节点的任何借用操作,都可能违反借用规则触发错误。
修复方案
不要写跨节点的链式连续调用,每一次borrow/borrow_mut拿到的守卫,要在单次操作完成后立刻释放,别让临时借用的生命周期覆盖后面的修改操作。可以把原来的链式调用拆成几步执行:
- 先临时拿到x的引用,取出要操作的目标节点(比如parent)的独立
Rc实例,操作完立刻释放x的借用(别把守卫存成长期变量) - 再对单独拿出来的目标节点调用
borrow_mut(),完成对应字段的修改
拆分后的参考写法:
// 原来的链式写法(有风险) // x.borrow_mut().parent.as_ref().unwrap().borrow_mut().left = Option::from(y.as_ref().unwrap().clone()); // 拆分后的安全写法 // 第一步:拿到目标parent节点,这一步执行完x的借用就自动释放了 let parent_node = x.borrow().parent.clone(); if let Some(parent) = parent_node { // 第二步:单独对parent节点做可变借用,完成修改 parent.borrow_mut().left = Some(y.clone().unwrap()); }
另外记得检查你构造的树结构,看看parent指针有没有自引用、循环引用的问题,避免本该指向其他节点的Rc不小心指向了节点自身。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

