考虑下面的代码
use std::{cell::RefCell, rc::Rc};
type NodeRef = Rc<RefCell<_Node>>;
#[derive(Debug)]
struct _Node {
id: usize,
data: Option<NodeRef>,
edges: Vec<NodeRef>,
}
impl _Node {
fn add(&mut self, other: NodeRef) {
println!("at {}", self.id);
self.data = match self.data.take() {
Some(current_data) => {
{
let mut current_data_raw = current_data.borrow_mut();
current_data_raw.id += other.borrow().id;
}
Some(current_data)
}
None => Some(Rc::clone(&other)),
};
for e in &self.edges {
e.borrow_mut().add(Rc::clone(&other));
}
println!("done {}", self.id);
}
}
#[derive(Debug)]
struct Node(NodeRef);
impl Node {
fn new(id: usize) -> Node {
Node(Rc::new(RefCell::new(_Node {
id,
data: None,
edges: vec![],
})))
}
fn add_edge(&self, other: &Node) {
self.0.borrow_mut().edges.push(Rc::clone(&other.0));
}
fn add(&self, other: Self) {
self.0.borrow_mut().add(other.0);
}
}
fn main() {
let a = Node::new(0);
let b = Node::new(1);
let c = Node::new(2);
let d = Node::new(3);
let e = Node::new(4);
let f = Node::new(5);
d.add_edge(&a);
d.add_edge(&b);
e.add_edge(&b);
e.add_edge(&c);
f.add_edge(&d);
f.add_edge(&e);
f.add(Node::new(6));
}
运行时生成的输出是
at 5
at 3
at 0
done 0
at 1
done 1
done 3
at 4
at 1
thread 'main' panicked at 'already mutably borrowed: BorrowError', src/libcore/result.rs:1009:5
这将创建一个图形
F--E--A
\ \
\ B
\ /
D
\
C
我试图在整个图中传播一个值,所以它从 F 开始,然后到达 E 和 D。从 E 到 A 和 B,没有任何错误。然后从 D 开始,运行时 panic 说可变借用的 RefCell
约束已被打破。
它似乎正在考虑从先前使用 B 调用回调的可变借用,然而,_Node::add
中的可变借用 (current_data_raw
) 有一个有限的范围,在范围结束后,我应该被允许再次可变地借用该值。从输出来看,当第二次为节点 B 调用该函数时,该函数的整个第一次调用已经退出,而不仅仅是可变借用范围。
我在这里错过了什么?
最佳答案
What am I missing here?
你的算法坏了。您可以通过将此调试代码添加到匹配的 Some
臂中来看到这一点:
{
let a = current_data.borrow();
let b = other.borrow();
assert_ne!(a.id, b.id);
}
这失败了:
thread 'main' panicked at 'assertion failed: `(left != right)`
left: `6`,
right: `6`', src/main.rs:23:25
您正在尝试同时两次借用完全相同的节点。
关于rust - 无法可变地借用 RefCell 内的内容,即使在前一个可变借用的范围已经结束之后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54277188/