How to pass a function that takes an iterator as a function parameter in Rust?

69 Views Asked by At

I want to pass a function that takes an arbitrary iterator over some type (e.g. String in the example below) into another function, but I don't know how to specify the type of such a function.

Here is a minimal (non-working) example of what I'm trying to achieve. The compiler cannot infer the type of I.

fn process<I>(lines: I)
where
    I: Iterator<Item = String>, // or IntoIterator
{
    for line in lines {
        println!("{}", line.to_uppercase());
    }
}

fn run<F, I>(processor: F)
where
    I: Iterator<Item = String>,
    F: Fn(I),
{
    let v = vec![
        String::from("aaa"),
        String::from("BBB"),
        String::from("cCcC"),
    ];
    processor(v.iter());
}

fn main() {
    run(process);
}
1

There are 1 best solutions below

0
cafce25 On BEST ANSWER

run isn't passing any Iterator<Item = String> it's currently passing a very specific std::slice::Iter<'_, String> so you can't have a generic I: Iterator on it. Anyways slice::Iter<'_, String> implements Iterator<Item = &String> not Iterator<Item = String> (note the additional/absent &) so process doesn't even accept it.

You probably meant to write this:

fn process<I>(lines: I)
where
    I: IntoIterator<Item = String>,
{
    for line in lines {
        println!("{}", line.to_uppercase());
    }
}

fn run<F>(processor: F)
where
    F: Fn(std::vec::IntoIter<String>),
{
    let v = vec![
        String::from("aaa"),
        String::from("BBB"),
        String::from("cCcC"),
    ];
    processor(v.into_iter());
}

fn main() {
    run(process);
}

or this alternative run:

fn run<F>(processor: F)
where
    F: Fn(Vec<String>),
{
    let v = vec![
        String::from("aaa"),
        String::from("BBB"),
        String::from("cCcC"),
    ];
    processor(v);
}