How to implement Iterator yielding mutable references [duplicate]

Your code is invalid because you try to return multiple mutable references to the same slice with the same lifetime 'a.

For such a thing to work, you would need a different lifetime for each returned Item so that you wouldn’t hold 2 mutable references to the same slice. You cannot do that for now because it requires Generic Associated Types:

type Item<'item> = &'item mut D; // Does not work today

One solution is to check that the indices are unique and to rebind the lifetime of the referenced item to 'a in an unsafe block. This is safe because all the indices are unique, so the user cannot hold 2 mutable references to the same item.

Don’t forget to encapsulate the whole code inside a module, so that the struct cannot be build without the check in new:

mod my_mod {
    pub struct LookupIterMut<'a, D> {
        data: &'a mut [D],
        indices: &'a [usize],
        i: usize,
    }

    impl<'a, D> LookupIterMut<'a, D> {
        pub fn new(data: &'a mut [D], indices: &'a [usize]) -> Result<Self, ()> {
            let mut uniq = std::collections::HashSet::new();
            let all_distinct = indices.iter().all(move |&x| uniq.insert(x));

            if all_distinct {
                Ok(LookupIterMut {
                    data,
                    indices,
                    i: 0,
                })
            } else {
                Err(())
            }
        }
    }

    impl<'a, D> Iterator for LookupIterMut<'a, D> {
        type Item = &'a mut D;

        fn next(&mut self) -> Option<Self::Item> {
            self.indices.get(self.i).map(|&index| {
                self.i += 1;

                unsafe { std::mem::transmute(&mut self.data[index]) }
            })
        }
    }
}

Note that your code will panic if one index is out of bounds.

Leave a Comment