Lionel Foxcroft
Lionel Foxcroft

Reputation: 1727

Why does this fail to compile?

I'm trying to get a reference to the tail of a linked list, and here's the code I wrote:

pub struct ListNode {
    pub next: Option<Box<ListNode>>,
}

fn tail(mut head: &mut Option<Box<ListNode>>) -> &mut Option<Box<ListNode>> {
    while let Some(x) = head.as_mut() {
        head = &mut x.next;
    }
    head
}

This fails to compile because it thinks I'm borrowing head as mutable twice. I was able to get to compile by changing it to this:

fn tail(mut head: &mut Option<Box<ListNode>>) -> &mut Option<Box<ListNode>> {
    while head.is_some() {
        head = &mut head.as_mut().unwrap().next;
    }
    head
}

It appears to me that these two functions do the exact same thing, but the first one looks a lot cleaner. Why doesn't it compile? Is there a better way of doing this than what I changed it to?

Upvotes: 2

Views: 66

Answers (1)

Silvio Mayolo
Silvio Mayolo

Reputation: 70257

You already have a value of the correct reference type, so the as_mut is unnecessary.

while let Some(x) = head {
    head = &mut x.next;
}
head

I can't speak to why your first example doesn't compile, as I'm still no expert in speaking "borrow checker" myself, but my guess is that Rust is just being conservative and assuming that the head.as_mut() borrow lasts into the variable x, which gets put into head, and therefore is a mutable borrow lasting as long as head does, whereas when we directly access it as I do above, Rust is smart enough to understand what's really happening.

Upvotes: 1

Related Questions