Storing an Iterator in a Box

Is there a way to make storing iterators less wordy?
I got something in principle like the following code, but wherever I am using the stream, I now have to sprinkle the <I: Iterator<Item=usize>>. If there are many usages, this becomes quite tedious, especially when considering that the type of stream source does not matter for using it.

struct Stream<I: Iterator<Item=usize>> {
    source: I,
}

impl<I: Iterator<Item=usize>> Stream<I> {
    fn new(source: I) -> Stream<I> {
        Stream { source }
    }
    
    fn advance(&mut self) -> Option<usize> {
        self.source.next()
    }
}

fn main() {
    let mut stream = Stream::new(0..8);
    assert_eq!(stream.advance(), Some(0));
}

I tried stuffing the iterator into a box. However, this does not compile due to the parameter type I may not live long enough.

struct Stream {
    source: Box<dyn Iterator<Item=usize>>,
}

impl Stream {
    fn new<I: Iterator<Item=usize>>(source: I) -> Stream {
        Stream { source: Box::from(source) }
    }
    
    fn advance(&mut self) -> Option<usize> {
        self.source.next()
    }
}

fn main() {
    let mut stream = Stream::new(0..8);
    assert_eq!(stream.advance(), Some(0));
}

Is there a way to make this work, or a different way to get rid of the iterator type parameter?

Boxing is the way for now.

The reason you're hitting a problem is that

means

source: Box<dyn Iterator<Item = usize> + 'static>

And thus you can't put things in the box that aren't I: 'static.

But that makes sense, if you look at the Stream type definition: there's no lifetime parameter, and there's no type parameter that could hold something with a lifetime. So there'd be no way for the compiler to check that any non-forever lifetime is correct.

If you want to be able to put non-: 'static things in your Stream, then it needs a lifetime:

struct Stream<'a> {
    source: Box<dyn Iterator<Item = usize> + 'a>,
}

Or if you're fine with it restricting it to : 'static things, you can change the constructor to say that:

impl Stream {
    fn new<I: Iterator<Item=usize> + 'static>(source: I) -> Stream {
        Stream { source: Box::from(source) }
    }
4 Likes

Oh, okay. That works, thanks! :slight_smile:
I did not know about that implicit 'static lifetime.