Error when playing with binary tree

Hi, I'm trying some simple algorithms with binary tree, but encountered some problems, and created this example: example_1.
Got error information like this:

   Compiling playground v0.0.1 (/playground)
warning: variable does not need to be mutable
  --> src/main.rs:28:9
   |
28 |     let mut cur = Some(Rc::clone(node_1.as_ref().unwrap()));
   |         ----^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0506]: cannot assign to `cur` because it is borrowed
  --> src/main.rs:32:13
   |
30 |     match cur.as_ref() {
   |           --- `cur` is borrowed here
31 |         Some(node) => {
32 |             cur = if let Some(left) = node.borrow().left.as_ref() {
   |             ^^^                       ------------- a temporary with access to the borrow is created here ...
   |             |
   |             `cur` is assigned to here but it was already borrowed
...
36 |             };
   |              - ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, TreeNode>`

For more information about this error, try `rustc --explain E0506`.
warning: `playground` (bin "playground") generated 1 warning
error: could not compile `playground` (bin "playground") due to 1 previous error; 1 warning emitted

However, after I changed this part

cur = if let Some(left) = node.borrow().left.as_ref() {
    Some(Rc::clone(left))
} else {
    None
};

to

let next = if let Some(left) = node.borrow().left.as_ref() {
    Some(Rc::clone(left))
} else {
    None
};
cur = next;

It worked, but the two versions looks quite similar.
And this is the playground link to the second version: example_2. I'm completely confused now, can anybody help me?

The return from .borrow() is like a mutex guard or similar: it holds on to a borrow of node and effectively locks the RefCell until dropped. When the borrow() was part of your if let statement, the guard wouldn't drop until after the entire statement -- after the assignment. But assigning to something which is still borrowed is an error.

In the changed version, the guard drops before the assignment.

This is a long but good article about temporary drop scopes and similar.


Your current version can be made a little more concise.

let left = node.borrow().left.as_ref().cloned();
cur = left;
2 Likes

Thank you so much! And I just found another post, someone mentioned the Temporary scopes, if I understand it correctly, my problem is similar to this one, right?

It's very related, yeah.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.