Cannot assign because it is borrowed

Hi,

When I try to build this code:

struct List {
    id: String,
    next: Option<Box<List>>,
}

impl List {
    fn remove_empty_node(&mut self) {
        let mut p = self;
        while let Some(n) = p.next.as_mut() {
            if n.id == "" {
                break;
            }
            p = n;
        }
        
        p.next = None;
    }
}

I get the following error:

error[E0506]: cannot assign to `p.next` because it is borrowed
  --> src/lib.rs:16:9
   |
9  |         while let Some(n) = p.next.as_mut() {
   |                             ------ borrow of `p.next` occurs here
...
16 |         p.next = None;
   |         ^^^^^^
   |         |
   |         assignment to borrowed `p.next` occurs here
   |         borrow later used here

I can't understand why the error is taking place here. Can somebody please shed some light?

Cheers,

If you google "rust linked list" you will find lots of people with similar issues and Introduction - Learning Rust With Entirely Too Many Linked Lists which you may find helpful.

I think this is a limitation of the borrow checker, though I'm not sure about the details of why it fails here...
I simplified the code to

    let mut p = self;
    if let Some(n) = p.next.as_mut() { // borrow of `p.next` occurs here
        p = n;
    }
    p.next = None; // assignment to borrowed `p.next` occurs here

and it's not obvious to me what the issue with doing this is. It works if p is a reference to a List created inside the function instead of self.

Thanks for the answer.

Indeed it looks like a limitation of the borrow checker. See below.

Removing the intermediate reference n also makes it work:

  let mut p = self;
  while let Some(p) = p.next.as_mut() {
    if p.id == "" {
      break;
    }
  }
  p.next = None;

I wonder why using an intermediate reference makes the borrow checker complain, though.

Does that do the same thing? My mental model says that the p inside the while let is a new binding that shadows the outer p.

1 Like

It doesn't do the same thing. The inner p shadows the outer, and the outer p is not modified.

It doesn't, as it turns out.

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.