I am learning Rust. For my first program, I wrote this code to maintain data about a partial ordering:
use std::collections::{HashMap, HashSet};
struct Node {
num_before: usize,
successors: HashSet<String>,
}
impl Node {
fn new() -> Node {
Node {
num_before: 0,
successors: HashSet::new(),
}
}
}
pub struct PartialOrdering {
node: HashMap<String, Node>,
}
impl PartialOrdering {
pub fn new() -> PartialOrdering {
PartialOrdering {
node: HashMap::new(),
}
}
pub fn get_node(&mut self, name: &String) -> &mut Node {
self.node.entry(name.clone()).or_insert_with(Node::new)
}
pub fn add_order(&mut self, before: &String, after: &String) {
let mut before_node = self.get_node(before);
if after != before {
let mut after_node = self.get_node(after);
if before_node.successors.insert(after.clone()) {
after_node.num_before += 1;
}
}
}
}
Compiling this code produces this error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> main.rs:35:25
|
33 | let before_node = self.get_node(before);
| ---- first mutable borrow occurs here
34 | if after != before {
35 | let mut after_node = self.get_node(after);
| ^^^^ second mutable borrow occurs here
36 | if before_node.successors.insert(after.clone()) {
| ---------------------- first borrow later used here
Admittedly I am new to the Rust borrowing rules, but this problem has me stumped. Please tell me what I am doing wrong, and how can I fix it?
Rc, the standard library's ref-counted pointer. Using that instead would enable you to take ownership of cheap copies of the node pointers, and thus not hold onto mutable borrows. - eggyalRcrequires "interior mutability" (i.e. run-time, rather than compile-time, borrow checking) which can be achieved withRefCell. Putting it together, you'd haveRc<RefCell<Node>>(albeitNodeitself would no longer need to contain the fields shown in your example above). - eggyalRwLockandMutexalso provide run-time borrow-checking at a bit of a higher level. These types are implemented usingUnsafeCell, as isRefCell---when it comes to interior mutability in rust, all roads point toUnsafeCell. - Emerson Harkinnum_beforefield, this code is from a Rust version of the tsort utility. The partial ordering of the tokens is created by callingadd_orderfor each pair of tokens read from input. For each token, thenum_beforefield is basically a count of the number of tokens known to be before it in the partial ordering, which is useful for generating thetsortoutput. - Frank Lhota