0

Why does this happen?

cannot use *last_node because it was mutably borrowed

#[derive(Debug)]
struct Node {
    data: i32,
    next: Link,
}

type Link = Option<Box<Node>>;

#[derive(Debug)]
struct List {
    size: i32,
    head: Link,
}

impl List {
    pub fn new() -> Self {
        List {
            size: 0,
            head: None,
        }
    }

    pub fn push(&mut self, data: i32) {
        let new_head = Box::new(Node {
            data: data,
            next: self.head.take(),
        });

        self.head = Some(new_head);
        self.size += 1;
    }

    pub fn append(&mut self, data: i32) {
        let new_node = Some(Box::new(Node {
            data: data,
            next: None,
        }));

        let mut last_node = &mut self.head;
        while let Some(node) = last_node {
            match node.next {
                None => break,
                Some(_) => last_node = &mut node.next,
            }
        }

        match last_node {
            None => self.head = new_node,
            Some(node) => node.next = new_node,
        }
        self.size += 1;
    }

    pub fn pop(&mut self) -> Option<i32> {
        let head = self.head.take();
        head.map(|node| {
            self.head = node.next;
            self.size -= 1;
            node.data
        })
    }
}

fn main() {
    let mut list = List::new();
    list.push(1);
    println!("{:?}", list);
    list.push(2);
    println!("{:?}", list);
    println!("{:?}", list.pop());
    list.push(3);
    println!("{:?}", list);
    list.push(4);
    println!("{:?}", list);
    list.append(5);
    println!("{:?}", list);
}

gives error

error[E0503]: cannot use `*last_node` because it was mutably borrowed
  --> src/main.rs:48:13
   |
40 |         while let Some(node) = last_node {
   |                        ---- borrow of `last_node.0` occurs here
...
48 |             None => self.head = new_node,
   |             ^^^^
   |             |
   |             use of borrowed `last_node.0`
   |             borrow later used here

error[E0499]: cannot borrow `last_node.0` as mutable more than once at a time
  --> src/main.rs:49:18
   |
40 |         while let Some(node) = last_node {
   |                        ---- first mutable borrow occurs here
...
49 |             Some(node) => node.next = new_node,
   |                  ^^^^
   |                  |
   |                  second mutable borrow occurs here
   |                  first borrow later used here

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0499, E0503.
For more information about an error, try `rustc --explain E0499`.

But this does not give error:

pub fn append(&mut self, data: i32) {
        let new_node = Some(Box::new(Node {
            data: data,
            next: None,
        }));

        let mut last_node = &mut self.head;
        while let Some(node) = last_node {
            last_node = &mut node.next
            //match node.next {
            //    None => break,
            //    Some(_) => last_node = &mut node.next,
            //}
        }

        match last_node {
            None => self.head = new_node,
            Some(node) => node.next = new_node,
        }
        self.size += 1;
    }
  • Does this answer your question? [Adding an append method to a singly linked list](https://stackoverflow.com/questions/43976787/adding-an-append-method-to-a-singly-linked-list) – kmdreko Feb 08 '21 at 03:53

1 Answers1

0

The borrow checker is finicky about conditional mutable re-borrows. Your second version that doesn't error is close to correct though:

pub fn append(&mut self, data: i32) {
    let new_node = Some(Box::new(Node {
        data: data,
        next: None,
    }));

    let mut last_node = &mut self.head;
    while let Some(node) = last_node {
        last_node = &mut node.next;
    }

    *last_node = new_node;
    self.size += 1;
}

See it in full on the playground.

I believe that the core issue with the original is that, because of the conditional match, the borrow checker considers both last_node and last_node.next to be borrowed at the same time even if they're actually the same variable. See the answer here for more information on this concept.

What you had written wasn't flawed, its just not currently accepted by the borrow checker.

kmdreko
  • 42,554
  • 6
  • 57
  • 106