How can I return a struct's mutable member from and iterator's next method without allocations?

Viewed 84

I have the following code:

struct MyIterator<'a> {
    data: &'a mut Vec<usize>,
}

impl<'a> Iterator for MyIterator<'a> {
    type Item = &'a [usize];

    fn next(&mut self) -> Option<Self::Item> {
        self.data.push(1); // Mutate the Vec.
        Some(&self.data)
    }
}

But get this compile error:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/lib.rs:10:14
   |
10 |         Some(&self.data)
   |              ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/lib.rs:8:13
   |
8  |     fn next(&mut self) -> Option<Self::Item> {
   |             ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:10:14
   |
10 |         Some(&self.data)
   |              ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/lib.rs:5:6
   |
5  | impl<'a> Iterator for MyIterator<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/lib.rs:8:46
   |
8  |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
9  | |         self.data.push(1);
10 | |         Some(&self.data)
11 | |     }
   | |_____^
   = note: expected `<MyIterator<'a> as Iterator>`
              found `<MyIterator<'_> as Iterator>`

For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground` due to previous error

I could do the following where I clone my data struct member:

struct MyIterator<'a> {
    data: &'a mut Vec<usize>,
}

impl<'a> Iterator for MyIterator<'a> {
    type Item = Vec<usize>;

    fn next(&mut self) -> Option<Self::Item> {
        self.data.push(1);
        let data = self.data.clone();
        Some(data)
    }
}

However don't want to allocate a new Vec with each call of next. Is there any way I can have the same logic without allocations?

1 Answers

What you want to do cannot be done in the way you have it. As @trentcl explains, as you iterate, you're returning references to data. That means, however, that the data is borrowed. If that is so, you cannot then go on and mutably mess with the data via push.

Related