Why does IterMut have the wrong lifetimes?

⚓ Rust    📅 2026-01-23    👤 surdeus    👁️ 1      

surdeus

I have a simple and straightforward implementation of an iterator over a slice:

struct Iter<'a, T> {
    slice: &'a [T],
}

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

    fn next(&mut self) -> Option<Self::Item> {
        let (first, rest) = self.slice.split_first()?;
        self.slice = rest;
        Some(first)
    }
}

The Iter struct contains a reference to a slice of T and iterates by splitting off the first element of the slice via <[T]>::split_first, setting self.slice to the remaining elements, and returning the reference to the first element inside Some. Very straightforward and understandable. Compiles fine and functions correctly.

But when I go to implement an iterator over mutable references to the elements of a slice using the same pattern, I get a lifetime error:

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

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

    fn next<'next>(&'next mut self) -> Option<Self::Item> {
        let (first, rest) = self.slice.split_first_mut()?;
        self.slice = rest;
        Some(first) // Error: Lifetime may not live long enough
    }
}

(playground)

The borrow checker complains that the Iterator::next method was supposed to return data with lifetime 'a but it is returning data with lifetime 'next.

Can someone provide an in-depth explanation of exactly what is going on here? Why does the return value of IterMut::next have lifetime 'next and not 'a? Why does IterMut::next have this problem but Iter::next does not? What exactly is different about &mut T compared to &T that causes this lifetime error in the &mut T case?

I also understand that the lifetime error in the IterMut case can be solved by taking the value out of self.slice with std::mem::take and then splitting that to get the reference to the first element like so:

 impl<'a, T> Iterator for IterMut<'a, T> {
     type Item = &'a mut T;
 
     fn next<'next>(&'next mut self) -> Option<Self::Item> {
-        let (first, rest) = self.slice.split_first_mut()?;
+        let slice = std::mem::take(&mut self.slice);
+        let (first, rest) = slice.split_first_mut()?;
         self.slice = rest;
         Some(first) // Error: Lifetime may not live long enough
     }
 }

Why does this work? Can you explain this fix and how it is different from the failing implementation above?

6 posts - 4 participants

Read full topic

🏷️ Rust_feed