The Issue
I’m trying to implement an iterator that yields windows (i.e. slices) into a buffer owned by the iterator itself – for example, if the buffer contains [0, 1, 2, 3, 4, 5]
, the iterator might yield [0, 1, 2, 3]
, [2, 3]
, or [3, 4, 5]
. Here’s a minimal example (Playground):
struct Slicer<'a> {
full: Vec<u32>,
cur_slice: &'a mut [u32]
}
impl<'a> Slicer<'a> {
fn new() -> Slicer<'a> {
let mut full = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
Slicer {
full: full, // Is there a way to transfer ownership of `full` here?
cur_slice: full.as_mut_slice()
}
}
}
impl<'a> Iterator for Slicer<'a>
{
type Item = &'a [u32];
fn next(&mut self) -> Option<&'a [u32]> {
if self.cur_slice.len() != 0 {
// In the actual program, this is streaming new data into the
// buffer. This is just an example of modifying the slice.
let len = self.cur_slice.len();
self.cur_slice = self.cur_slice[..len - 1].as_mut();
Some(self.cur_slice) // Getting a lifetime error here…
} else {
None
}
}
}
fn main() {
let mut slicer = Slicer::new();
while let Some(x) = slicer.next() {
println!("{x:?}");
}
}
This results in two separate errors: error[E0515]: cannot return value referencing local variable `full`
and error: lifetime may not live long enough
. Full errors:
error[E0515]: cannot return value referencing local variable `full` --> srcmain.rs:11:9 | 11 | / Slicer { 12 | | full: full, 13 | | cur_slice: full.as_mut_slice() | | ---- `full` is borrowed here 14 | | } | |_________^ returns a value referencing data owned by the current function
error: lifetime may not live long enough --> srcmain.rs:26:13 | 16 | impl<'a> Iterator for Slicer<'a> | -- lifetime `'a` defined here ... 20 | fn next(&mut self) -> Option<&'a [u32]> { | - let's call the lifetime of this reference `'1` ... 26 | Some(self.cur_slice) // Getting a lifetime error here… | ^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
Now, from what I understand, this counts as an iterator that refers to itself – which an Iterator
is unable to do (because the signature of next
doesn’t include an explicit lifetime for &mut self
– with fairly good reason, from what I understand). This appears to be a perfect use case for lending iterators (as mentioned in this previous StackOverflow answer, and in fact, a window iterator is the primary example in the docs), but I attempted an implementation using a lending iterator, and was presented with exactly the same errors.
The Question
How does one fix this? Is there a way to make the lending iterator approach work? Is there a different composition that achieves the same effect?
(Note that I can’t copy the data, as that would defeat the purpose of the iterator, which is meant to be a more ergonomic interface into parsing a particular file format with a lot of data.)