How to use Rust's Peekable?

Peekable is not a trait and thus cannot be used as a bound, which would suggest that it could mean one of many types. It is a single, specific, concrete type, struct Peekable<A, T>. As you have observed, it’s constructed by calling the peekable() method on an iterator, which changes it to something that is peekable.

Here’s how you’d use it if you just wanted to take an iterator:

fn trawl<I, E>(iter: I) where I: Iterator<Result<char, E>> {
    let pk = pk.peekable();
    …
}

Note also that the peekable() method takes self by value; you can’t take a mutable reference to an iterator there.

The alternative which is what you were aiming for but which I would be generally less inclined towards, would be to require the argument to be peekable, putting the burden onto the caller, as you had:

fn trawl<I, E>(pk: Peekable<E, I>) where I: Iterator<Result<char, E>> {
    …
}

Peekable is actually a struct, not a trait. If you wanted to take a Peekable, you could define your function like this:

fn trawl<E, I>(it: Peekable<I>) where I: Iterator<Result<char, E>> {
    ...
}

Your second implementation is failing to compile because peek takes self by value (i.e. it consumes the iterator, returning a new one), so you can't call it through a &mut reference. Most code simply takes the iterator by value instead of by reference:

fn trawl<E, I>(it: I) where I: Iterator<Result<char, E>> {
    let it = it.peekable();
    ...
}

If you don't want to move the iterator into a function like trawl, you can use the by_ref() method to create a new iterator that holds onto an &mut reference:

let mut my_iterator = /* whatever */;
trawl(my_iterator.by_ref());
// my_iterator is still usable here

As far as style goes, I would say that the second form is the better way to go, as the first leaks what's basically an implementation detail.


Rust has changed a bit since the previous answers. The way to do it now is:

fn trawl<I, E>(pk: Peekable<I>) 
where I: Iterator<Item = Result<char, E>> {
    …
}

Tags:

Rust