CodeBlanks Logo Icon CodeBlanks

Lazy evaluation

Learn the lazy nature of iterators.

Lazy evaluation

Adapters are lazy: nothing is computed until a consuming method is called. That's why the compiler warns "iterators are lazy and do nothing unless consumed" for a map whose result isn't used:

let it = [1, 2, 3].iter().map(|x| {
    println!("işleniyor {x}");
    x * 10
});
println!("henüz yok");          // nothing processed yet
let ilk: Vec<i32> = it.take(2).collect();   // only 1 and 2 are processed

Thanks to laziness, even infinite iterators are used safely: (1..).map(|n| n * n).take(3).

Why laziness helps

Chained adapters don't create intermediate collections; each element passes through the whole pipeline one by one. The compiler usually turns such a chain into code as fast as a hand-written loop (a zero-cost abstraction):

// no intermediate Vec is created
let t: u64 = (1..=1_000_000u64)
    .filter(|n| n % 2 == 0)
    .map(|n| n * 3)
    .sum();

inspect(|x| ..) is handy in debugging for seeing values in the middle of the pipeline.

Practice Lazy pipeline

Write the example above: create a map printing işleniyor N for each element, print henüz yok first, then collect with take(2) and print the vector.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
fn main() {
    let veri = [1, 2, 3];
    let it = veri.iter().map(|x| {
        println!("işleniyor {}", x);
        x * 10
    });
    println!("henüz yok");
    let ilk: Vec<i32> = it.take(2).collect();
    println!("{:?}", ilk);
}

Expected output

henüz yok
işleniyor 1
işleniyor 2
[10, 20]

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 How much work does <code>(1..).filter(|n| n % 7 == 0).next()</code> do?

  • It loops forever
  • It lists all numbers
  • It doesn't compile
  • It only tries 1 through 7 and returns Some(7) Correct answer

Explanation: next asks for only one element; the chain stops at the first match.

2 Take the first few

Question
let ilk: Vec<i32> = it.____(2).collect();
Answer
let ilk: Vec<i32> = it.take(2).collect();

Explanation: take asks only for the first n elements; the rest is never processed.

3 Expression and behaviour

Term Meaning
v.iter().map(f); Does nothing
v.iter().map(f).count() f runs on each element
(1..).take(3) Safe slice of infinity
inspect(|x| ..) Observe in between

All lessons in Intermediate