user1949917
user1949917

Reputation:

How can I return an iterator over a slice?

fn main() {
    let vec: Vec<_> = (0..5).map(|n| n.to_string()).collect();

    for item in get_iterator(&vec) {
        println!("{}", item);
    }
}

fn get_iterator(s: &[String]) -> Box<Iterator<Item=String>> {
    Box::new(s.iter())
}

Upvotes: 1

Views: 234

Answers (1)

Shepmaster
Shepmaster

Reputation: 431599

fn get_iterator<'a>(s: &'a [String]) -> Box<Iterator<Item=&'a String> + 'a> {
    Box::new(s.iter())
}

The trick here is that we start with a slice of items and that slice has the lifetime 'a. slice::iter returns a slice::Iter with the same lifetime as the slice. The implementation of Iterator likewise returns references with that lifetime. We need to connect all of the lifetimes together.

That explains the 'a in the arguments and in the Item=&'a part. So what's the + 'a mean? There's a complete answer about that, and another with more detail. The short version is that an object with references inside of it may implement a trait, so we need to account for those lifetimes when talking about a trait. By default, that lifetime is 'static as it was determined that was the usual case.

The Box is not strictly required, but is a normal thing you'll see when you don't want to deal with the complicated types that might underlie the implementation (or just don't want to expose the implementation). In this case, the function could be

fn get_iterator<'a>(s: &'a [String]) -> std::slice::Iter<'a, String> {
    s.iter()
}

But if you add .skip(1), the type would be:

std::iter::Skip<std::slice::Iter<'a, String>>

And if you involve a closure, then it's currently impossible to specify the type, as closures are unique, anonymous, auto-generated types! A Box is required for those cases.

Upvotes: 1

Related Questions