I've encountered a problem that I cannot understand involving mutable references and borrow checker.
I am writing a naive binary search tree using safe rust. Full code can be seen here: https://github.com/adensur/rust_learning/blob/master/bst/src/lib.rs
This is the node and the tree itself:
struct Node {
key: i64,
left_ptr: Option<Box<Node>>,
right_ptr: Option<Box<Node>>,
}
#[derive(Default)]
pub struct BstSet {
root: Option<Box<Node>>,
len: usize,
}
Here is the insert function (similar to HashSet::insert()), and it works:
pub fn insert(&mut self, key: i64) -> bool {
let mut node_ptr = &mut self.root;
while let Some(node) = node_ptr {
match node.key.cmp(&key) {
Ordering::Equal => return false,
Ordering::Less => {
node_ptr = &mut node.right_ptr;
}
Ordering::Greater => {
node_ptr = &mut node.left_ptr;
}
}
}
*node_ptr = Some(Box::new(Node {
key,
left_ptr: None,
right_ptr: None,
}));
self.len += 1;
true
}
I try to move this code to a function for some code reuse, and it doesn't compile:
fn find_node_mut(&mut self, key: i64) -> &mut Option<Box<Node>> {
let mut node_ptr = &mut self.root;
while let Some(node) = node_ptr {
match node.key.cmp(&key) {
Ordering::Equal => break,
Ordering::Less => {
//node_ptr = &mut node_ptr.as_mut().unwrap().right_ptr;
node_ptr = &mut node.right_ptr;
}
Ordering::Greater => {
// node_ptr = &mut node_ptr.as_mut().unwrap().left_ptr;
node_ptr = &mut node.left_ptr;
}
}
}
node_ptr
}
Giving me this error:
error[E0499]: cannot borrow `*node_ptr` as mutable more than once at a time
--> src/lib.rs:61:9
|
46 | fn find_node_mut(&mut self, key: i64) -> &mut Option<Box<Node>> {
| - let's call the lifetime of this reference `'1`
47 | let mut node_ptr = &mut self.root;
48 | while let Some(node) = node_ptr {
| ---- first mutable borrow occurs here
...
61 | node_ptr
| ^^^^^^^^
| |
| second mutable borrow occurs here
| returning this value requires that `node_ptr.0` is borrowed for `'1`
For more information about this error, try `rustc --explain E0499`.
Why does it work in one case but not the other? What is the correct way to reason about this to be able to predict what the compiler would say?
After fiddling about with the code I've found a (somewhat more messy) way to write it so that it works (the commented lines in the code), but the fact that I don't understand why this is happening is bothering me.