Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop over boxed iterator?

Note: This question is obsolete since Rust 1.0. The Iterator trait now has an associated type, Item, instead of a type parameter and a blanket Iterator implementation was added for Box<Iterator>.

I want to define a trait method that returns an iterator. I want to avoid specifying what the actual return type is, so until we have unboxed abstract return types, I'm using trait objects. This means the method returns Box<Iterator<A>>. But I'm not sure how to use a boxed trait object. I can't iterate over an object of type Box<Iterator<A>>:

fn main() {
    let xs = vec![0u, 1, 2, 3];
    let boxed_iter = box xs.iter() as Box<Iterator<&uint>>;
    for x in boxed_iter {}
}

This errors with "for" loop expression does not implement the "Iterator" trait.

So my question is: How can I iterate over Box<Iterator<A>>. Or, more generally, how can I used boxed trait objects?

like image 684
awelkie Avatar asked Aug 21 '14 21:08

awelkie


People also ask

What does collect () do in Rust?

collect() can take all the values in an Iterator 's stream and stick them into a Vec . And the map method is now generating Result<i32, &str> values, so everything lines up.

How do you consume an iterator in Rust?

fn last(self) -> Option<Self::Item> Consumes the iterator, returning the last element. This method will evaluate the iterator until it returns None . While doing so, it keeps track of the current element. After None is returned, last() will then return the last element it saw.

Can you use an iterator twice?

Iterators can generally not be iterated twice because there might be a cost to their iteration. In the case of str::lines , each iteration needs to find the next end of line, which means scanning through the string, which has some cost.

Are Rust iterators lazy?

In Rust, iterators are lazy, meaning they have no effect until you call methods that consume the iterator to use it up. For example, the code in Listing 13-10 creates an iterator over the items in the vector v1 by calling the iter method defined on Vec<T> . This code by itself doesn't do anything useful.


1 Answers

The issue is that Box<Iterator<A>> does not itself implement the Iterator trait. (I'm not sure exactly why, perhaps someone else can chime in on that point.)

You could remedy this yourself with:

impl<A> Iterator<A> for Box<Iterator<A>> {
    fn next(&mut self) -> Option<A> { self.next() }
}

But since neither type nor trait are defined in your crate, this is not allowed. To work around this, you could define your own sub-trait of Iterator, implement Iterator<A> for all Box<MyIter<A>> and then implement MyIter<A> for all types I that satisfy Iterator<A>:

trait MyIter<A> : Iterator<A> {}
impl<A, I: Iterator<A>> MyIter<A> for I {}

// This is now allowed because `MyIter` is defined in this crate.
impl<A> Iterator<A> for Box<MyIter<A>> {
    fn next(&mut self) -> Option<A> { self.next() }
}

And you'd have to change your code to use as Box<MyIter<&uint>>:

fn main() {
    let xs = vec![0u, 1, 2, 3];
    let mut boxed_iter = box xs.iter() as Box<MyIter<&uint>>;
    for x in boxed_iter { println!("{}", x); }
}

(I added mutability to boxed_iter since it is required for iterators.)

like image 62
BurntSushi5 Avatar answered Sep 28 '22 21:09

BurntSushi5