0

I have defined some simple iterator types Iter and IterMut for immutable and mutable views respectively. These types are effectively just containers around a slice and an usize index.

The implementation of the immutable Iter variant compiles fine without any issues; however, as soon as the mut keyword is added to the borrows and output type, the compiler begins to complain about the lifetime possibly not living long enough. The exact error is the commonly seen error of:

error: lifetime may not live long enough
  --> <source>:13:7
   |
6  | impl<'a, T: 'a> Iterator for IterMut<'a, T> {
   |      -- lifetime `'a` defined here
...
9  |   fn next(&mut self) -> Option<&'a mut T> {
   |           - let's call the lifetime of this reference `'1`
...
13 |       Some(&mut self.data[self.index]) // Error occurs here!
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: aborting due to previous error

What is puzzling to me is that the code between Iter and IterMut varies only by the presence of mut. The code that triggered the above error is:

pub struct IterMut<'a, T: 'a> {
  data: &'a mut [T],
  index: usize,
}

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

  fn next(&mut self) -> Option<&'a mut T> {
    self.index += 1;

    if self.index < self.data.len() {
      Some(&mut self.data[self.index]) // Error occurs here!
    } else {
      None
    }
  }
}

Whereas nearly identical code with only mut removed compiles fine:

pub struct Iter<'a, T: 'a> {
  data: &'a [T],
  index: usize,
}

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

  fn next(&mut self) -> Option<&'a T> {
    self.index += 1;

    if self.index < self.data.len() {
      Some(&self.data[self.index]) // this works
    } else {
      None
    }
  }
}

Live Example


I understand that the diagnostic is suggesting adding a lifetime parameter to &self (although this would violate the definition of Iterator), but it's really not clear to me why this is needed only if mut is present.

Why does the presence of mut make the compiler think that a lifetime isn't satisfied? What would the appropriate fix for this be?

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
  • Mutable references have more restrictions than immutable references, namely they must be exclusive. The way the compiler enforces that is the lifetime of `&mut self.data[self.index]` is bound to `self`, and not `'a`. You'll either need to use `unsafe` to transmute the lifetimes, or preferably just build off the existing iterator types for slices that do this for you already. – kmdreko Feb 01 '23 at 04:20
  • @kmdreko Thanks for the link, I've marked to close the question as a duplicate! I know about mutable exclusivity, but I didn't realize it would consider this aliasing, given the way that it operates. Oh well. Using the existing iter types isn't quite an option for my purposes though. The example I constructed for this question is effectively a `slice::Iter`, but the real one is more complex. I guess I need to rethink this. – Human-Compiler Feb 01 '23 at 04:24

0 Answers0