“Cell”和“RefCell”
Cell
and RefCell
implement what Rust calls interior mutability: mutation of values in an immutable context.
“Cell”通常用于简单类型,因为它需要复制或移动值。更复杂的内部类型通常使用“RefCell”,它会在运行时跟踪已共享和专有的引用,并在这些引用被滥用时 panic。
use std::cell::RefCell; use std::rc::Rc; #[derive(Debug, Default)] struct Node { value: i64, children: Vec<Rc<RefCell<Node>>>, } impl Node { fn new(value: i64) -> Rc<RefCell<Node>> { Rc::new(RefCell::new(Node { value, ..Node::default() })) } fn sum(&self) -> i64 { self.value + self.children.iter().map(|c| c.borrow().sum()).sum::<i64>() } } fn main() { let root = Node::new(1); root.borrow_mut().children.push(Node::new(5)); let subtree = Node::new(10); subtree.borrow_mut().children.push(Node::new(11)); subtree.borrow_mut().children.push(Node::new(12)); root.borrow_mut().children.push(subtree); println!("graph: {root:#?}"); println!("graph sum: {}", root.borrow().sum()); }
- 在此示例中,如果我们使用的是“Cell”而非“RefCell”,则必须将“Node”从“Rc”中移出以推送子项,然后再将其移回原位。这是安全的做法,因为单元格中总是有一个未引用的值,但这不符合人体工程学。
- 如需使用 Node 执行任何操作,您必须调用“RefCell”方法,通常为“borrow”或“borrow_mut”。
- 演示可以通过向“subtree.children”添加“root”来创建引用循环(不要尝试输出它!)。
- 为了演示运行时 panic,请添加一个会递增“self.value”并以相同方法调用其子项的“fn inc(&mut self)”。如果存在引用循环,就会 panic,并且“thread”“main”会因“already borrowed: BorrowMutError”而 panic。