0

I am trying to write a mutable iterator over a vector, but I am unable to figure out what the compiler is trying to tell me. Here is my implementation

struct IterMut<'a> {
    vec: &'a mut Vec<u32>,
    index: usize,
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u32;

    fn next(&mut self) -> Option<Self::Item> {
        let item = if self.index < self.vec.len() {
            Some(&mut self.vec[self.index])
        } else {
            None
        };

        self.index += 1;

        item
    }
}

And the compiler error is:

error: lifetime may not live long enough
  --> src/main.rs:60:9
   |
48 | impl<'a> Iterator for IterMut<'a> {
   |      -- lifetime `'a` defined here
...
51 |     fn next(&mut self) -> Option<Self::Item> {
   |             - let's call the lifetime of this reference `'1`
...
60 |         item
   |         ^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

The non mutable version compiles and works.

struct Iter<'a> {
    vec: &'a Vec<u32>,
    index: usize,
}

impl<'a> Iterator for Iter<'a> {
    type Item = &'a u32;

    fn next(&mut self) -> Option<Self::Item> {
        let item = if self.index < self.vec.len() {
            Some(&self.vec[self.index])
        } else {
            None
        };

        self.index += 1;

        item
    }
}

Here is a playground link with the code to try out.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
rozina
  • 4,120
  • 27
  • 49

1 Answers1

2

The problem is that your IterMut holds on to the elements already passed.

It can do so only by reborrowing the item but this now means that the item isn't borrowed from the original Vec any more but from the IterMut instead so it does not live long enough. (The reborrow only lives as long as the IterMut, not as long as the original Vec.

In nightly or once take_first_mut stabilizes you can do this:

#![feature(slice_take)]
struct IterMut<'a> {
    vec: &'a mut [u32],
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u32;

    fn next(&mut self) -> Option<Self::Item> {
        self.vec.take_first_mut()
    }
}

Note I switched from &mut Vec<u32> to a slice because you have to be able to 'release' the items which is not easy with a Vec


As @ChayimFriedman pointed out on stable you can do it with mem::take in the meantime:

struct IterMut<'a> {
    vec: &'a mut [u32],
}

impl<'a> Iterator for IterMut<'a> {
    type Item = &'a mut u32;

    fn next(&mut self) -> Option<Self::Item> {
        let (first, rem) = std::mem::take(&mut self.vec).split_first_mut()?;
        self.vec = rem;
        Some(first)
    }
}
cafce25
  • 15,907
  • 4
  • 25
  • 31