This question already has answers here:
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
(4 answers)
Closed 4 years ago.
To learn Rust, I am implementing an AVL tree/dictionary. To insert a new element, I descend into the tree until I find a node where it could be inserted. Unfortunately it complains about several issues with borrowing pointers, and I'm having trouble deciphering them.
I've highlighted where and which errors occur.
enum AVLTree<T, U> {
Tree(T, U, Box<AVLTree<T, U>>, Box<AVLTree<T, U>>),
Empty,
}
impl<T, U> AVLTree<T, U>
where T: PartialOrd + PartialEq + Copy,
U: Copy
{
fn insert_element(&mut self, key: T, val: U) {
let new_node = AVLTree::Tree(key, val, Box::new(AVLTree::Empty), Box::new(AVLTree::Empty));
if let AVLTree::Empty = *self {
*self = new_node;
return;
}
let mut at = self;
loop {
match at {
&mut AVLTree::Tree(key2, _, ref mut left, ref mut right) => {
// ^~~~~~~~~~~~
// error: cannot borrow `at.2` as mutable more than once at a time
// ^~~~~~~~~~~~~
// error: cannot borrow `at.3` as mutable more than once at a time
if key < key2 {
if let AVLTree::Empty = **left {
*left = Box::new(new_node);
break;
}
at = &mut **left;
// error: cannot assign to `at` because it is borrowed
} else {
if let AVLTree::Empty = **right {
*right = Box::new(new_node);
break;
}
at = &mut **right;
// error: cannot assign to `at` because it is borrowed
}
}
&mut AVLTree::Empty => unreachable!(),
}
}
// Do something
}
}
Why is deconstructing at borrowing it? Why is the compiler complaining about multiple mutable borrows when this should never happen? How could this code be written instead to avoid such errors?
This seems to be a weakness of the borrow checker, and is perhaps a bug. The problem is that you are borrowing at in the match and then modifying it. Unfortunately, the compiler doesn't see that the at inside the loop and outside the loop are conceptually different. We can make them explicitly different, however:
enum AVLTree {
Tree(Box<AVLTree>),
Empty,
}
impl AVLTree {
fn insert_element(&mut self) {
let mut at = self;
loop {
let tmp_at = at; // Main change
match tmp_at {
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!()
}
}
}
}
fn main() {}
Here, we transfer the mutable borrow from at to tmp_at, then transfer it to left, then transfer it back to at.
A prettier option may be to use a new scope:
fn insert_element(&mut self) {
let mut at = self;
loop {
match {at} { // Main change
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!(),
}
}
}
Related
Sorry if this is a dumb question, I'm relatively new with Rust and just can't crack this double mutable borrowing error. I'm trying to create an AVL tree method that finds an appropriate position into which a new node can be inserted. I don't understand what I need to do for the first borrow to drop.
I'm trying to do this without RC, RefCell or Unsafe - though it's becoming increasingly unclear to me if my approach is feasible.
Rust Playground Link
pub fn find_pos(&mut self, key: &K) -> &mut Link<K, V>{
let mut current = &mut self.root;
while let Some(node) = current.as_mut() { // <- first mutable borrow
match node.key.cmp(&key) {
Ordering::Equal => break,
Ordering::Greater => {
current = &mut node.right;
},
Ordering::Less => {
current = &mut node.left;
},
}
};
current // <- second mutable borrow
}
I've also tried something similar to the solution described here, with no luck.
pub fn find_pos(&mut self, key: &K) -> &mut Link<K, V> {
let mut current = &mut self.root;
loop {
let tmp = current;
if let Some(ref mut node) = *tmp {
match node.key.cmp(&key) {
Ordering::Equal => {
current = tmp;
break
},
Ordering::Greater => {current = &mut node.right},
Ordering::Less => {current = &mut node.left},
}
} else {
current = tmp;
break
}
}
current
}
This is a known limitation of the borrow checker. The next-gen Polonius will solve this.
In the meantime, the solution (without unsafe) is to repeat the calculation. In your case, this means some unwrap()s:
pub fn find_pos(&mut self, key: &K) -> &mut Link<K, V> {
let mut current = &mut self.root;
while current.as_mut().is_some() {
match current.as_mut().unwrap().key.cmp(&key) {
Ordering::Equal => break,
Ordering::Greater => {
current = &mut current.as_mut().unwrap().right;
}
Ordering::Less => {
current = &mut current.as_mut().unwrap().left;
}
}
}
current
}
See also:
Cannot borrow as mutable in loop
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
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.
The main error here is that you have a &mut Option<Box<Node>>, but that doesn't makes much sense, you probably want an Option<&mut Box<Node>>. Thing of it as finding or not something, that Option doesnt need to be a referenced mutable.
With that, you can leverage as_mut and and_then to get your code started, then some modifications to checks inside the loop:
impl BstSet {
fn find_node_mut(&mut self, key: i64) -> Option<&mut Box<Node>> {
self.root.as_mut().and_then(|mut node_ptr| loop {
match node_ptr.key.cmp(&key) {
Ordering::Equal => return Some(node_ptr),
Ordering::Less => {
if let Some(right) = node_ptr.right_ptr.as_mut() {
node_ptr = right;
} else {
return None
}
}
Ordering::Greater => {
if let Some(left) = node_ptr.left_ptr.as_mut() {
node_ptr = left;
} else {
return None
}
}
}
})
}
}
Playground
Seems like this thread Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in? that refers to a known issue https://github.com/rust-lang/rust/issues/21906#issuecomment-73296543 answers my question.
Running my program with Polonius borrow checker also seems to work:
RUSTFLAGS="-Z polonius" cargo +nightly test
And here is the perfect video explaining just the thing: https://www.youtube.com/watch?v=_agDeiWek8w
How to properly reason about this to determine why does insert function compile, and find_node_mut doesn't:
In both functions, node and node_ptr are used interchangeably, so their scope sort of "overlaps".
In insert function, the compiler is able to properly determine the "liveness" of the loans: the variable is "dead" if it is about to get written to (current value cannot be referenced in the future). That way, even though the two mutable references have overlapping scopes, their 'lifetimes', represented by a set of lines, do not overlap.
In find_node_mut, the reference is returned from the function, blowing out the lifetime of the reference from a small set of lines to some "unknown" lifetime 'a, covering at least the entire function body.
I'm playing around with building a very simple stack based evaluator in Rust and I've come up against an odd situation where I think the borrow checker is being too conservative:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
type Op = Box<dyn Fn(&mut Evaluator) -> Result>;
type OpTable = HashMap<String, Op>;
pub struct Evaluator {
stack: Vec<Value>,
ops: OpTable,
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Evaluator {
fn add(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y + x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
fn sub(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y - x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: OpTable = HashMap::new();
ops.insert("+".to_string(), Box::new(Evaluator::add));
ops.insert("-".to_string(), Box::new(Evaluator::sub));
Evaluator { stack, ops }
}
pub fn eval(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
// user definition
if let (Some(&":"), Some(&";")) = (symbols.first(), symbols.last()) {
if symbols.len() > 3 {
let statement = symbols[2..symbols.len() - 1].join(" ");
self.ops.insert(
symbols[1].to_string().to_ascii_lowercase(),
Box::new(move |caller: &mut Evaluator| caller.exec(&statement)),
);
return Ok(());
} else {
return Err(Error::InvalidWord);
}
}
self.exec(input)
}
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) { // <--------------errors here
f(self)?; // <----------------------------|
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +");
println!("{:?}", e.stack);
e.eval(": plus-1 1 + ;");
e.eval("4 plus-1");
println!("{:?}", e.stack);
}
I'm getting:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:77:21
|
76 | if let Some(f) = self.ops.get(&s) {
| -------- immutable borrow occurs here
77 | f(self)?;
| -^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
For more information about this error, try `rustc --explain E0502`.
error: could not compile `evaluator` due to previous error
I believe this is because taking part of the hashmap (f) borrows all of self immutably, then I'm passing self mutably to f(). However, there is no real conflict here (I think).
I'm able to get around this by actually removing and reinserting the value:
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if self.ops.contains_key(&s) {
let f = self.ops.remove(&s).unwrap();
if let Err(e) = f(self) {
self.ops.insert(s, f);
return Err(e);
}
self.ops.insert(s, f);
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
But this feels hacky and is a lot more verbose and inefficient. Am I missing something? Is there a way to tell the compiler the first version is ok?
The compiler is entirely correct, and so is your explanation: The call to get() needs a borrow on self.ops to return an &Op of the same lifetime. You then try to call that FnMut with a mutable borrow of self; this mutable borrow of self aliases with the immutable borrow on self.ops, and in theory it would be possible for an implementation of this FnMut to modify that borrowed Op through self, which is not allowed. The compiler prevented a situation where mutation occurs through an aliased pointer.
This situation often occurs when passing &mut self around, as immutable borrows on members of self which result in more borrows (&self.ops.get() has the same lifetime as &self) "lock" all of self.
While your second example is cumbersome, it is at least correct as proven by the compiler: By removing Op from the hashtable, the FnMut can't reach itself through self anymore, and mutation while aliasing is prevented.
A better approach is usually to avoid taking &mut self as an argument (&mut self as in &mut Executor).
This question already has answers here:
Cannot move out of value which is behind a shared reference when unwrapping
(2 answers)
error[E0507]: Cannot move out of borrowed content
(1 answer)
cannot move out of borrowed content when unwrapping a member variable in a &mut self method
(2 answers)
Closed 4 years ago.
Why can't I do this?
pub fn start_workers(&mut self) {
// start all the worker threads
self.dispatch_thread = Some(spawn(||{
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_secs(1));
}
}));
self.dispatch_thread.unwrap().join();
}
I'm getting the following error,
error[E0507]: cannot move out of borrowed content
--> src/orderbook.rs:195:9
|
195 | self.dispatch_thread.unwrap().join();
| ^^^^ cannot move out of borrowed content
This is indeed a non-obvious error message. Have a look at the method signatures for unwrap:
pub fn unwrap(self) -> T
and take:
pub fn take(&mut self) -> Option<T>
unwrap consumes the Option (note the receiver is self), which would leave self.dispatch_thread in an unknown state. If you use take it is returned to the None state as you probably intended.
You probably want take in this context; as shown here:
use std::thread;
use std::time;
struct Foo {
foo: Option<thread::JoinHandle<()>>,
}
impl Foo {
fn nope(&mut self) {
self.foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
self.foo.take().unwrap().join();
}
}
fn main() {
let foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
foo.unwrap().join();
let mut foo = Foo { foo: None };
foo.foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
foo.foo.unwrap().join();
let mut foo = Foo { foo: None };
foo.nope();
}
Note that assert!(foo.foo.is_none()); would be similarly illegal; but is valid in this case because we don't violate that constraint. In the method with &self as a receiver, this isn't true, which is why it is illegal in that case.
This question already has answers here:
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
(4 answers)
Closed 4 years ago.
To learn Rust, I am implementing an AVL tree/dictionary. To insert a new element, I descend into the tree until I find a node where it could be inserted. Unfortunately it complains about several issues with borrowing pointers, and I'm having trouble deciphering them.
I've highlighted where and which errors occur.
enum AVLTree<T, U> {
Tree(T, U, Box<AVLTree<T, U>>, Box<AVLTree<T, U>>),
Empty,
}
impl<T, U> AVLTree<T, U>
where T: PartialOrd + PartialEq + Copy,
U: Copy
{
fn insert_element(&mut self, key: T, val: U) {
let new_node = AVLTree::Tree(key, val, Box::new(AVLTree::Empty), Box::new(AVLTree::Empty));
if let AVLTree::Empty = *self {
*self = new_node;
return;
}
let mut at = self;
loop {
match at {
&mut AVLTree::Tree(key2, _, ref mut left, ref mut right) => {
// ^~~~~~~~~~~~
// error: cannot borrow `at.2` as mutable more than once at a time
// ^~~~~~~~~~~~~
// error: cannot borrow `at.3` as mutable more than once at a time
if key < key2 {
if let AVLTree::Empty = **left {
*left = Box::new(new_node);
break;
}
at = &mut **left;
// error: cannot assign to `at` because it is borrowed
} else {
if let AVLTree::Empty = **right {
*right = Box::new(new_node);
break;
}
at = &mut **right;
// error: cannot assign to `at` because it is borrowed
}
}
&mut AVLTree::Empty => unreachable!(),
}
}
// Do something
}
}
Why is deconstructing at borrowing it? Why is the compiler complaining about multiple mutable borrows when this should never happen? How could this code be written instead to avoid such errors?
This seems to be a weakness of the borrow checker, and is perhaps a bug. The problem is that you are borrowing at in the match and then modifying it. Unfortunately, the compiler doesn't see that the at inside the loop and outside the loop are conceptually different. We can make them explicitly different, however:
enum AVLTree {
Tree(Box<AVLTree>),
Empty,
}
impl AVLTree {
fn insert_element(&mut self) {
let mut at = self;
loop {
let tmp_at = at; // Main change
match tmp_at {
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!()
}
}
}
}
fn main() {}
Here, we transfer the mutable borrow from at to tmp_at, then transfer it to left, then transfer it back to at.
A prettier option may be to use a new scope:
fn insert_element(&mut self) {
let mut at = self;
loop {
match {at} { // Main change
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!(),
}
}
}