The current implementation of Iterator
requires that objects returned from next()
remain valid for the lifetime of the iterator, which works great when you have a collection of objects to iterate over. Unfortunately it does not work when you have a collection of “views” of an object which only remain valid for a short period of time. For example:
#[deriving(Show)]
struct View<'a, 'b> {
_landscape: &'b mut Landscape<'a>
}
#[deriving(Show)]
struct Landscape<'a>;
impl<'a> Landscape<'a> {
fn iter<'b>(&'a mut self) -> LandscapeIterator<'b, 'a> {
LandscapeIterator {
landscape: self
}
}
}
struct LandscapeIterator<'a, 'b> {
landscape: &'b mut Landscape<'a>,
}
impl<'a, 'b> LandscapeIterator<'a, 'b> {
fn next<'c>(&'c mut self) -> Option<View<'a, 'c>> {
Some(View { _landscape: self.landscape })
}
}
fn main() {
let mut landscape = Landscape;
let mut iter = landscape.iter();
loop {
let view = iter.next();
println!("view: {}", view);
break;
}
}
In this example, we want to iterate over a number of different views of a landscape - only one view is valid at a time. Here it is not possible to implement Iterator, since the definition of next()
does not match the definition in Iterator
due to the lifetime parameter, and Iterator<View<'a, 'c>>
could not be used in the definition since the lifetime would not be in scope. Since Iterator isn’t implemented, a for loop cannot be used (at least, it can’t be since https://github.com/rust-lang/rust/commit/caa564bea3d5f5a24d0797c4769184c1ea0abaff).
I encountered this scenario while writing some low-level networking code, where each call to next()
would either read into a buffer, then return a slice of the buffer; or if the buffer already contains packets, simply return a slice. It would seem there is currently no nice way to provide an Iterator
for such a stream of packets, and instead a loop like the one above must be used.
I don’t currently have a proposal to support Iterator
for short-lived objects, but would be interested to know if there are any clever tricks which could enable this.