Open
Description
Recently I have seen a lot of (new) users struggle with code like this:
pub struct IterMut<'a, T> {
inner: &'a mut Vec<T>,
index: usize,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.get_mut(self.index);
self.index += 1;
item
}
}
This doesn't compile, of course:
error: lifetime may not live long enough
--> src/lib.rs:12:9
|
6 | impl<'a, T> Iterator for IterMut<'a, T> {
| -- lifetime `'a` defined here
...
9 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
...
12 | item
| ^^^^ associated function was supposed to return data with lifetime `'a`
but it is returning data with lifetime `'1`
This is often seen as a shortcoming of the language, as a pattern that is correct but the compiler doesn't understand - which in this case, is not untrue. But in many impls do involve overlapping mutable references, which would be unsound.
As for improvements, I have some ideas:
- Reassure the user that they really do need that lifetime, and that they didn't put a wrong lifetime somewhere. Say something like "The contract of
Iterator::next
demands an item with at least the lifetime 'a" - Explain splitting borrows. In my experience this clicks well, and users are often surprised they don't need to reach for unsafe code. We should explain this in-line or link to the nomicon.
- Explain why the iterator trait has the lifetime requirements that it has ,e.g. "
the_iter.collect();
is a thing"