面试题答案
一键面试使用RefCell实现树形数据结构
- 定义树形结构:
use std::cell::RefCell; use std::rc::Rc; struct TreeNode { value: i32, children: RefCell<Vec<Rc<TreeNode>>>, } impl TreeNode { fn new(value: i32) -> Rc<TreeNode> { Rc::new(TreeNode { value, children: RefCell::new(Vec::new()), }) } fn add_child(&self, child: Rc<TreeNode>) { self.children.borrow_mut().push(child); } fn modify_child(&self, index: usize, new_child: Rc<TreeNode>) { let mut children = self.children.borrow_mut(); if index < children.len() { children[index] = new_child; } } }
- 这里使用
Rc
(引用计数智能指针)来共享节点,RefCell
来在运行时检查借用规则。 TreeNode
结构体包含一个整数值value
和一个RefCell<Vec<Rc<TreeNode>>>
类型的children
字段,用于存储子节点。add_child
方法通过borrow_mut
获取可变借用,然后将新的子节点添加到children
向量中。modify_child
方法同样通过borrow_mut
获取可变借用,根据给定的索引修改子节点。
- 这里使用
可能出现的Cell或RefCell相关的运行时错误及避免方法
BorrowMutError
错误:- 原因:当有不可变借用(
borrow
)存在时,尝试获取可变借用(borrow_mut
)会导致此错误。例如:
let root = TreeNode::new(0); let _imm_ref = root.children.borrow(); // 下面这行代码会触发BorrowMutError root.children.borrow_mut();
- 避免方法:确保在获取可变借用之前,没有任何不可变借用存在。可以通过提前结束不可变借用的作用域来避免,例如:
let root = TreeNode::new(0); { let _imm_ref = root.children.borrow(); // 不可变借用作用域结束 } root.children.borrow_mut();
- 原因:当有不可变借用(
- 双重可变借用错误:
- 原因:如果在同一时间对
RefCell
获取多个可变借用,会导致此错误。例如:
let root = TreeNode::new(0); let mut children1 = root.children.borrow_mut(); // 下面这行代码会触发双重可变借用错误 let mut children2 = root.children.borrow_mut();
- 避免方法:确保同一时间只有一个可变借用。注意合理安排代码逻辑,不要在需要同时获取多个可变借用的情况下使用
RefCell
。如果确实需要多个可变借用,可以考虑使用更复杂的并发原语或数据结构设计。
- 原因:如果在同一时间对