Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I handle/circumvent "Cannot assign to ... which is behind a & reference" in Rust?

I'd implementing a simple linked list. This is the (working) code I had so far:

pub struct LinkedList<T> {
    start: Option<Box<Link<T>>>,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        return LinkedList { start: None };
    }
}

struct Link<T> {
    value: Box<T>,
    next: Option<Box<Link<T>>>,
}

impl<T> Link<T> {
    fn new_end(value: T) -> Link<T> {
        return Link::new(value, None);
    }

    fn new(value: T, next: Option<Box<Link<T>>>) -> Link<T> {
        return Link {
            value: Box::new(value),
            next,
        };
    }
}

Next on the list is a method to append to the list; this is what I came up with:

pub fn append(&mut self, element: T) {
    // Create the link to append
    let new_link = Some(Box::new(Link::new_end(element)));

    // Find the last element of the list. None, if the list is empty
    let mut last = &self.start;
    while let Some(link) = last {
        last = &link.next;
    }

    // Insert the new link at the correct position
    match last {
        None => self.start = new_link,
        Some(last) => last.next = new_link, // This fails
    }
}

The precise compiler error is

error[E0594]: cannot assign to `last.next` which is behind a `&` reference

I vaguely get the problem; you cannot mutate an immutable reference. But making the references mutable does seem to make the errors even worse.

How does one handle these kinds of errors? Is there a simple quick-fix, or do you structure your code completely different in Rust?

like image 998
Islion Avatar asked Jan 14 '20 08:01

Islion


1 Answers

Your code almost worked. It will if you bind mutably:

impl<T> LinkedList<T> {
    pub fn append(&mut self, element: T) {
        // Create the link to append
        let new_link = Some(Box::new(Link::new_end(element)));

        // Find the last element of the list. None, if the list is empty
        let mut last = &mut self.start;
        while let Some(link) = last {
            last = &mut link.next;
        }

        // Insert the new link at the correct position
        match last {
            None => self.start = new_link,
            Some(ref mut last) => last.next = new_link,
        }
    }
}

FYI, the answer to this recent question is very good at clarifying the matter about mutability, type and binding in Rust.

like image 51
edwardw Avatar answered Oct 19 '22 14:10

edwardw