Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Borrow vs mutable borrow strange failure in lifetimes

While trying to implement an iterator which yields mutable refs to elements of a linked list, I stumbled upon a strange issue.

This works fine:

impl<'a, T> Iterator<&'a T> for LinkedListIterator<'a, T>{
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cell(ref x, ref xs) => {self.current = &**xs; Some(x)},
            &End                 => None
        }
    }
}

But this doesn't work; the compiler says lifetime of self is too short to guarantee its contents can be safely reborrowed:

impl<'a, T> Iterator<&'a mut T> for LinkedListMutIterator<'a, T>{
    fn next(&mut self) -> Option<&'a mut T> {
        match self.current {
            &Cell(ref mut x, ref mut xs) => {self.current = &mut **xs; Some(x)},
            &End                         => None
        }
    }
}

I would expect that either both example work, or both do not, but I can't understand how borrowing something as mutable vs not-mutable would impact the way the compiler checks for lifetimes. Surely if something lives long enough to be safely borrowed, it lives long enough to be safely mutably borrowed?

EDIT: Here is the definition of both Iterators:

pub struct LinkedListIterator<'a, T> 
    current: &'a LinkedList<T>
}

pub struct LinkedListMutIterator<'a, T> {
    current: &'a mut LinkedList<T>
}

LinkedLisk:

#[deriving(Eq, Clone)]
pub enum LinkedList<T> {
    Cell(T, ~LinkedList<T>),
    End
}

For a complete view of the file, please see https://github.com/TisButMe/rust-algo/blob/mut_iter/LinkedList/linked_list.rs

like image 801
Thomas P Avatar asked Nov 02 '22 07:11

Thomas P


1 Answers

Note that you've left out the definition(s) of LinkedListMutIterator for the two variant bits of code, which might be relevant to any real attempt to reproduce and dissect your problem.


So, I'll try to guess at what's going on.

The compiler error message here might be misleading you; there are other factors beyond the lifetime of self that may be relevant here.

In particular I suspect the borrow-checker is complaining because it is trying to ensure that you are not creating multiple mutable-borrows that alias the same state.

  • It is sound to have multiple immutable-borrows to the same piece of state...

  • ... but you cannot have multiple mutable-borrows to the same piece of state (because we want to ensure that if you have a &mut reference to some state, then that reference is the only way to mutate the state).

like image 122
pnkfelix Avatar answered Nov 11 '22 22:11

pnkfelix