genericsrusthigher-order-functions

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


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);
}

Solution

  • 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);
    }