skills_getting_rusty
skills_getting_rusty

Reputation: 23

Lifetime may not live long enough

I've defined a struct which only has a slice of element of type T.

pub struct MyStruct<'a, T> {
    slice: &'a mut [T],
}

I want to define an Iterator for MyStruct which yields a MyStruct with a slice which has 10 elements.

impl<'a, E> Iterator for MyStruct<'a, E> {
    type Item = MyStruct<'a, E>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.slice.len() < 10 {
            return None;
        } else {
            let (head, tail) = self.slice.split_at_mut(10);

            self.slice = tail;

            Some(MyStruct { slice: head })
        }
    }
}

But unfortunately I'm lifetime issues.

error: lifetime may not live long enough
  --> src/lib.rs:12:32
   |
5  | impl<'a, E> Iterator for MyStruct<'a, E> {
   |      -- lifetime `'a` defined here
...
8  |     fn next(&mut self) -> Option<Self::Item> {
   |             - let's call the lifetime of this reference `'1`
...
12 |             let (head, tail) = self.slice.split_at_mut(10);
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`

I'm not an expert in lifetime and would appreciate it if someone could point out to me what I'm doing incorrectly here.

Upvotes: 2

Views: 940

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71350

The question How can I create my own data structure with an iterator that returns mutable references? does a good job explaining why it is disallowed. But despite what said, or at least implied there that it is impossible to do that without unsafe code ("Now you may wonder: How did the standard library authors manage to write the mutable vector iterator? The answer is simple: They used unsafe code."), for pure slices it is actually possible.

The trick is simple: instead of using self.slice from the restrictive self reference, replace it with an empty slice and now we have the slice with the full lifetime:

fn next(&mut self) -> Option<Self::Item> {
    if self.slice.len() < 10 {
        return None;
    } else {
        let slice = std::mem::take(&mut self.slice);
        let (head, tail) = slice.split_at_mut(10);
        self.slice = tail;
        Some(MyStruct { slice: head })
    }
}

Upvotes: 3

Related Questions