2

I am writing a parser and needed a lookahead from an iterator but did not want to use the Peekable trait. Instead, I used a wrapper for the iterator. I came up with something like this, omitting everything unnecessary:

struct Wrapper<'a> {
    it: &'a mut Iterator<Item = &'a String>,
}

pub trait DoSomething {
    fn do_something(self);
}

impl<'a, T> DoSomething for T
where
    T: IntoIterator<Item = &'a String>,
{
    fn do_something(self) {
        let mut it = self.into_iter();
        let throwaway = Wrapper { it: &mut it };
    }
}

This fails to compile with:

error[E0309]: the associated type `<T as std::iter::IntoIterator>::IntoIter` may not live long enough
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as std::iter::IntoIterator>::IntoIter: 'a`...
note: ...so that the type `<T as std::iter::IntoIterator>::IntoIter` is not borrowed for too long
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^

error[E0309]: the associated type `<T as std::iter::IntoIterator>::IntoIter` may not live long enough
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as std::iter::IntoIterator>::IntoIter: 'a`...
note: ...so that the type `<T as std::iter::IntoIterator>::IntoIter` will meet its required lifetime bounds
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^

Although I do not understand why this is necessary (question 1), I added T::IntoIter: 'a to the where clause in the impl. This fails with:

error[E0597]: `it` does not live long enough
  --> src/main.rs:16:44
   |
16 |         let throwaway = Wrapper { it: &mut it };
   |                                            ^^ borrowed value does not live long enough
17 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 9:1...
  --> src/main.rs:9:1
   |
9  | / impl<'a, T> DoSomething for T
10 | | where
11 | |     T: IntoIterator<Item = &'a String>,
12 | |     T::IntoIter: 'a,
...  |
17 | |     }
18 | | }
   | |_^

I don't understand either why it does not live long enough, as the deallocation order should be throwaway and then it. Using a second lifetime 'b also does not work, either with 'a: 'b or with 'b: 'a (I was frustrated and just tried every combination).

The only thing that helped was to separate the lifetimes of the Iterator reference and its contained references and relating them (no need to specify the lifetime of T::IntoIter):

struct Wrapper<'a, 'b: 'a> {
    it: &'a mut Iterator<Item = &'b String>,
}

Why?

It makes sense to say "The item references have to live at least as long as the iterator reference", but what I don't get is why they can't be the same and why the error messages are hinting at the Wrapper construction instead of the definition, where changing lifetimes did not help at all.

I found the official documentation regarding lifetimes pretty confusing. It doesn't get into if lifetime annotations actually change anything in the compiled code regarding deallocation or if it's just aiding the static analysis without actually changing the real lifetime of a piece of memory.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Quidrex
  • 51
  • 3

1 Answers1

1

&'a mut Iterator<Item = &'a String> means that the lifetimes of the reference to the iterator and the references returned by the iterator have to be able to be unified (to 'a).

Declaring that the iterator and the iterator's references have distinct lifetimes allows the code to compile:

struct Wrapper<'i, 's: 'i> {
    it: &'i mut Iterator<Item = &'s String>,
}

There's no need to add T::IntoIter: 'a.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366