`IterMut` implementation

I'm implementing a Stack and would like to add Iterator support, and running into the situation that Iter is ok however with the same pattern IterMut fails.

Would like some help with this.

pub struct Iter<'a, T: 'a> {
top: usize,
data: &'a [T],
}

impl<'a, T: 'a> Iterator for Iter<'a, T> {
type Item = &'a T;

fn next(&mut self) -> Option<Self::Item> {
    if self.top == 0 {
        return None;
    }
    self.top -= 1;
    self.data.get(self.top)
}

}

pub struct IterMut<'a, T: 'a> {
top: usize,
data: &'a mut [T],
}

impl<'a, T: 'a> Iterator for IterMut<'a, T> {
type Item = &'a mut T;

fn next(&mut self) -> Option<Self::Item> {
    if self.top == 0 {
        return None;
    }
    self.top -= 1;
    self.data.get_mut(self.top) // error here : lifetime may not live long enough
}

}

You have to split the slice up to avoid aliasing. On mobile but here's a page about it:

4 Likes

For example:

impl<'a, T: 'a> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let (item, rest) = std::mem::take(&mut self.data).split_last_mut()?;
        self.data = rest;
        Some(item)
    }
}
3 Likes

This is expected, because the iterator must return non-overlapping unique &mut references, but the borrow checker can't verify that.

Borrow checker only checks based on the "shape" of the code (scopes, order of execution), but it has no way of reasoning at all about run-time values, so it won't be able to check whether your top is used correctly or not.

You either need to use an existing function to iterate, or use unsafe to force through the lifetimes (carefully!)

2 Likes

Thanks for the response. This gets clear :+1: cc @quinedot , @kornel