Iterators

One of the great things about being a Perl programmer is that we get to read Higher-Order Perl. And one of the great things about Higher-Order Perl is the explanation of iterators.

Rust iterators are a joy to use. They really make Rust fun. If you think a "low-level" systems language is going to be tedious to use, you're in for a treat. If you like to use things like map and grep in Perl, you're going to love Rust.

For loops

Earlier, I mentioned revisiting Rust's for loop. Let's do that now. It looks like this

fn main() {
    let names = vec!["Hank", "Dean", "Brock"];

    for name in names {
        println!("Hello, {}!", name);
    }
}

But this is really syntactic sugar for something like this

fn main() {
    let names = vec!["Hank", "Dean", "Brock"];

    let mut iterator = names.into_iter();

    while let Some(name) = iterator.next() {
        println!("Hello, {}!", name);
    }
}

That is, Rust for loops are not really a separate thing. They are just an alternate syntax for consuming iterators.

Rust has an Iterator trait that we can use to define our own iterators. Then we can use for loops on them.

Lazy

Rust iterators are lazy. That means they must be consumed before they do anything. If we write this

fn main() {
    let names = vec!["Hank", "Dean", "Brock"];

    let hellos = names.iter().map(|name| format!("Hello, {}!", name));
    
    println!("{:#?}", hellos);
}

then nothing happens. We've set the machine up, but we haven't turned the crank. We have to do something like collect it into a vector to do that.

fn main() {
    let names = vec!["Hank", "Dean", "Brock"];

    let hellos = names.iter().map(|name| format!("Hello, {}!", name)).collect::<Vec<_>>();
    
    println!("{:#?}", hellos);
}

Being lazy also means that iterators can be infinite.