Is passing an iterator to a function as an argumen

2019-07-13 20:19发布

问题:

This question already has an answer here:

  • How to write a Rust function that takes an iterator? 3 answers

Say I have a string, from which I make an iterator (cycle-able, peek-able) over its chars:

let hello = "hello";
let mut iterator = hello.chars().cycle().peekable;

I wanted to figure out what the type of iterator is, so I purposefully introduced an error:

let mut iterator: usize = hello.chars().cycle().peekable;

The compiler then informed me that the type of the right hand side is:

std::iter::Peekable<std::iter::Cycle<std::str::Chars<'_>>>

Wow, that's a mouthful. If I define a function like so:

fn foobar(x: std::iter::Peekable<std::iter::Cycle<std::str::Chars<'_>>>){
    // snip
}

I get an error like this:

error: underscore lifetimes are unstable (see issue #44524)

So, if I want to pass an iterator to a function, how should I do so? Or, is this something I should avoid?

回答1:

Ok so there are multiple aspects to this questions:

First of, you can avoid the compiler error by giving it an explicit lifetime:

fn foobar<'a>(mut x: std::iter::Peekable<std::iter::Cycle<std::str::Chars<'a>>>){

To the he second question, whether this is idiomatic or not, i'd say no, avoid this specific approach.

You can only pass in this specific Iterator chain - something else is not possible. But most of the times, your algorithm isn't interested in the specific combination, rather than the functionality to "produce" chars. Use generics orimpl Trait instead (if you have access to nightly rust).

Impl Trait is a feature, which allows hiding the specific type used. This specific feature, accepting impl traits in argument position landed as of a few days ago, at the time of writing. I made this quick sketch for demonstration purposes, playground link

#![feature(universal_impl_trait)]

fn main() {
    foo("hello".chars());
    foo("hello".chars().rev());
}

fn foo(x: impl Iterator<Item=char>) {
    let text: String = x.collect();
    println!("{}", &text)
}

Edit: You can use generics as well, see comments from nullqube and stefan



标签: rust