Need help understand why borrowing fails when scope is used

Why this fails Playground link

#[derive(Debug, Clone)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Self {
        Node { value, next: None }
    }
}

fn main() {
    let mut head = &mut Box::new(Node::new(1));

    let next_node = Box::new(Node::new(2));
    let  next_next_node = Box::new(Node::new(3));

    head.next = Some(next_node);

    match &mut head.next {
        Some(next) => head = next,
        None => {}
    };

    head.next = Some(next_next_node);
    println!("Curr ->{:#?}", head);
}

Above ends up with an error

   Compiling playground v0.0.1 (/playground)
error[E0506]: cannot assign to `head.next` because it is borrowed
  --> src/main.rs:26:5
   |
21 |     match &mut head.next {
   |           -------------- `head.next` is borrowed here
...
26 |     head.next = Some(next_next_node);
   |     ^^^^^^^^^
   |     |
   |     `head.next` is assigned to here but it was already borrowed
   |     borrow later used here

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

From the error message, not sure if I understand it right, I get that next is borrowed as mutable, but it's moved to curr and later being used again like what happens in next example.
But why compiler isn't happy about same in the above example :frowning:

While this works Playground link

#[derive(Debug, Clone)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Self {
        Node { value, next: None }
    }
}

fn main() {
    let mut head = &mut Box::new(Node::new(1));

    let next_node = Box::new(Node::new(2));
    let next_next_node = Box::new(Node::new(3));

    head.next = Some(next_node);

    let next = head.next.as_mut().unwrap();
    head = next;

    head.next = Some(next_next_node);
    println!("Curr ->{:#?}", head);
}

And this too works when ref is used Playground link

#[derive(Debug, Clone)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Self {
        Node { value, next: None }
    }
}

fn main() {
    let mut head = &mut Box::new(Node::new(1));

    let next_node = Box::new(Node::new(2));
    let  next_next_node = Box::new(Node::new(3));

    head.next = Some(next_node);

    match head.next {
        Some(ref mut next) => head = next,
        None => {}
    };

    head.next = Some(next_next_node);
    println!("Curr ->{:#?}", head);
}

Thank you

In this case head.next is still borrowed because head is not replaced when None is matched. This isn't true in the second example that works, where head is replaced unconditionally.

I'm not sure why ref mut works in the third example, so hopefully someone else will answer.

1 Like

This is not a precise explanation, but: the borrow checker is bad at reasoning about borrows that are, conditionally, either dropped or used later, after the conditional/loop structure ends. With the ref mut, the mutable borrow is only taken when it is used (when the Some match arm matches), so the borrow checker does not have to figure out that &mut head.next is guaranteed not to be in use in the None case.

The more common situation where this comes up is conditionally returning a mutable borrow, then trying to use another borrow of the same place if the function did not return. This is known as “NLL Problem case #3”.

Someday, the borrow checker may be smarter. For now, ref mut is a useful tool.

3 Likes

Thank you @jumpnbrownweasel

Thank you @kpreid

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.