Hi
Assume I have a graph structure
struct Node;
struct Graph {
nodes: Vec<RefCell<Node>>,
}
With this it is possible to get multiple mutable references to nodes as long as there are no references to the same node.
impl Graph {
fn get_mut(&self, index: usize) -> RefMut<'_, Node> {
self.nodes[index].borrow_mut()
}
}
This is all well and good, however it is a bit more free than I would like.
You see this allows one to get mutable references to nodes even when holding only a non-mutable reference to the graph. It is safe of course since the RefCell guarantees this, but it makes for a more confusing code base when one cannot trust that methods taking a non-mut reference do in fact not mutate it.
I have been trying to fix this by using the signature below (i.e. just taking &mut self
instead of &self
)
impl Graph {
fn get_mut(&mut self, index: usize) -> RefMut<'_, Node> {
self.nodes[index].borrow_mut()
}
}
However this makes it impossible to borrow multiple (different) nodes at the same time
let mut graph = Graph {
nodes: vec![RefCell::new(Node{}), RefCell::new(Node{})]
};
let mut a = graph.get_mut(0);
let mut b = graph.get_mut(1);
a.mutate();
b.mutate();
error[E0499]: cannot borrow `graph` as mutable more than once at a time
--> src/something.rs:933:17
|
932 | let mut a = graph.get_mut(0);
| ----- first mutable borrow occurs here
933 | let mut b = graph.get_mut(0);
| ^^^^^ second mutable borrow occurs here
934 | a.mutate();
| - first borrow later used here
Is there a way to convince the borrow checker fulfill the requirements below?
- Only allow the method to be used if you have a mutable reference
- Allow multiple mutable references to different nodes (dynamically checked by
RefCell
or some similar unsafe code).
My best attempt has involved using a trait that I only implement for &mut Graph
. And while this does work, it cannot be used if you have a mutable value and not a reference, and it gives very uninformative error message if you try to use it on a &Graph
(not mutable).