Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Cannot assign because it is borrowed the temporary

I have the following code with two almost identical functions. One of them does not compile.

struct Node {
    pub data: i32,
    pub next: Option<Rc<RefCell<Node>>>,
    pub prev: Option<Weak<RefCell<Node>>>
}

impl Node {
    pub fn new(data: i32) -> Rc<RefCell<Self>> {
        Rc::new(RefCell::new(Self {
            data,
            next: None,
            prev: None
        }))
    }
}


fn print_iterate_doesnt_work(node: &Rc<RefCell<Node>>) {
    let mut current_node = node.clone();
    loop {
        current_node = {
            let current_node_ref = current_node.borrow();
            print!("{} ", current_node_ref.data);
            if current_node_ref.next.is_none() { 
                return; 
            }

            // This line doesn't work
            current_node.borrow().next.as_ref().unwrap().clone() 
        }
    }
}

fn print_iterate_works(node: &Rc<RefCell<Node>>) {
    let mut current_node = node.clone();
    loop {
        current_node = {
            let current_node_ref = current_node.borrow();
            print!("{} ", current_node_ref.data);
            if current_node_ref.next.is_none() { 
                return; 
            }

            // This one works
            current_node_ref.next.as_ref().unwrap().clone()
        }
    }
}

As I understand current_node.borrow() creates temporary Ref. Why doesn’t compiler see that i don’t use current_node and the temporary Ref. It says:

cannot assign to `current_node` because it is borrowed
the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
borrow occurs due to deref coercion to `RefCell<Node>`rustcClick for full compiler diagnostic
main.rs(44, 13): `current_node` is borrowed here

main.rs(44, 13): a temporary with access to the borrow is created here ...

main.rs(46, 5): ... and the borrow might be used here, when that temporary is dropped 
and runs the destructor for type `Ref<'_, Node>`

rc.rs(1564, 5): deref defined here

main.rs(44, 13): for example, you could save the expression's value in a new local variable `x` 
and then make `x` be the expression at the end of the block: `let x = `, `; x`

I actually don’t fully understand ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type 'Ref<'_, Node>'

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

As a result I don’t understand why should I save the expression's value in a new local variable 'x' and then make 'x' be the expression at the end of the block: 'let x = ', '; x'

Cargo check:

error[E0506]: cannot assign to `current_node` because it is borrowed
    --> src\main.rs:39:9
     |
39   |         current_node = {
     |         ^^^^^^^^^^^^ `current_node` is assigned to here but it was already borrowed
...
45   |             current_node.borrow().next.as_ref().unwrap().clone() //
     |             ---------------------
     |             |
     |             `current_node` is borrowed here
     |             a temporary with access to the borrow is created here ...
46   |         }
47   |     }
     |     - ... and the borrow might be used here, when that temporary is dropped and runs the 
destructor for type `Ref<'_, Node>`
     |
     = note: the temporary is part of an expression at the end of a block;
             consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
     = note: borrow occurs due to deref coercion to `RefCell<Node>`

So what’s going on here?

>Solution :

Your non working version is equivalent to this:

fn print_iterate_doesnt_work(node: &Rc<RefCell<Node>>) {
    let mut current_node = node.clone();
    loop {
        let current_node_ref = current_node.borrow();
        print!("{} ", current_node_ref.data);
        if current_node_ref.next.is_none() { 
            return; 
        }
        
        current_node = current_node.borrow().next.as_ref().unwrap().clone();  
    }
}

Now the problem is that the temporary current_node.borrow() isn’t dropped until the end of the statement. But at that time current_node has already been replaced.

The working example works, because it stores the temporary in a block scoped variable, which is dropped before returning from the block, so also before reassigning current_node so everything works out.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading