Hi all,
I'm attempting to create a new type that wraps a complex iterator. The type owns some data of its own, and then creates an iterator over that data and passes values from that iterator out of its own next()
method. Because the internal iterator is complex, I'm type erasing it and storing it in a Box rather than writing out the full type name in the struct declaration. Here's my reduced code example:
struct A<'a> {
some_numbers: Vec<i32>,
other_numbers: Vec<i32>,
iter: Option<Box<dyn Iterator<Item = i32> + 'a>>,
}
impl<'a> A<'a> {
fn new(some: Vec<i32>, other: Vec<i32>) -> A<'a> {
A {
some_numbers: some,
other_numbers: other,
iter: None,
}
}
}
impl<'a> Iterator for A<'a> {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.iter {
Some(ref mut iter) => iter.as_mut().next(),
None => {
let mut new_iter = self
.some_numbers
.iter()
.chain(self.other_numbers.iter())
.cloned();
let next_item = new_iter.next();
self.iter = Some(Box::new(new_iter));
next_item
}
}
}
}
fn main() {
let some: Vec<i32> = (0..12).collect();
let other: Vec<i32> = (42..84).collect();
let a = A::new(some, other);
println!("{:?}", a.collect::<Vec<i32>>());
}
The error I get here is this:
error: lifetime may not live long enough
--> src/main.rs:30:17
|
17 | impl<'a> Iterator for A<'a> {
| -- lifetime `'a` defined here
...
20 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
...
30 | self.iter = Some(Box::new(new_iter));
| ^^^^^^^^^ assignment requires that `'1` must outlive `'a`
If I understand correctly, the iterator I'm creating in the body of next()
may go away at the end of the None
block, despite being Boxed and assigned to self.iter
. I'm confused by this. Shouldn't the assignment pass ownership of that iterator to self
?
Another thing I'm not totally sure of in this example is the type of the internal iterator: Option<Box<dyn Iterator<Item = i32> + 'a>>
. Does the + 'a
at the end read "this value will live as long as A"?
A way I've tried to correct the error is by declaring a new lifetime on the next()
method, apply it the &mut self
, and constrain it to live as long as 'a
. I get a different error with that approach:
error[E0195]: lifetime parameters or bounds on method `next` do not match the trait declaration
--> src/main.rs:20:12
|
20 | fn next<'b: 'a>(&'b mut self) -> Option<Self::Item> {
| ^^^^^^^^ lifetimes do not match method in trait
I gues that's because the Iterator trait doesn't declare a lifetime?
I've spent enough time on this that I'm thinking I may be fundamentally misunderstanding something, or just taking the wrong approach to solving this. Is there another way I should be thinking about how to build this struct?
Thanks a lot!