Zero-cost, measured
Worked examples
Read the claim, then run it and check the machine agrees. One at a time — nothing here is taken on trust.
fn loop_form(n: u64) -> u64 {
let mut total = 0u64;
for i in 0..n {
if i % 2 == 0 { total += i * i; }
}
total
}
fn iter_form(n: u64) -> u64 {
(0..n).filter(|i| i % 2 == 0).map(|i| i * i).sum()
}
fn main() {
for n in [0, 1, 10, 50, 100] {
let a = loop_form(n);
let b = iter_form(n);
println!("n={n:3}: loop={a:6} iter={b:6} agree={}", a == b);
}
}
Two implementations, one answer every time. iter_form's .sum()
infers u64 from the return type; the closures in filter/map
are inlined away. The printed agree=true on every row is the
whole point — the abstraction changed how the code reads, not what
it computes.
use std::time::Instant;
fn loop_form(n: u64) -> u64 {
let mut total = 0u64;
for i in 0..n {
if i % 2 == 0 { total += i * i; }
}
total
}
fn iter_form(n: u64) -> u64 {
(0..n).filter(|i| i % 2 == 0).map(|i| i * i).sum()
}
fn main() {
let n = 2_000_000;
let t = Instant::now();
let a = loop_form(n);
let loop_ns = t.elapsed().as_nanos();
let t = Instant::now();
let b = iter_form(n);
let iter_ns = t.elapsed().as_nanos();
println!("results equal: {}", a == b);
println!("loop: {loop_ns} ns, iter: {iter_ns} ns (timing is noisy)");
}
The deterministic line is results equal: true. The two timings
will be close and their order can flip run to run — this is a debug
build with no -O, on a shared machine, so treat the numbers as a
demonstration that neither form is categorically slower, not as a
benchmark. Under -O both compile to the same fused loop.
fn main() {
let n = 6u64;
// Zero-cost: no intermediate storage, fused into one loop.
let summed: u64 = (0..n).filter(|i| i % 2 == 0).map(|i| i * i).sum();
// NOT free: collect() allocates a Vec to hold the evens.
let collected: Vec<u64> = (0..n).filter(|i| i % 2 == 0).collect();
println!("summed = {summed}"); // 0 + 4 + 16 = 20
println!("collected = {collected:?} (heap allocated)");
}
sum() folds straight to a number — no storage, the pipeline
fuses. collect() is different: it materializes a Vec, which
allocates on the heap. That allocation is a real cost you asked for,
not iterator overhead — exactly the distinction the "zero-cost"
promise draws. Prints summed = 20 and collected = [0, 2, 4].
Check the concept
One question at a time. Unsure? Revisit the lecture, then answer.
The challenge
Pass the quiz to unlock the challenge — your code will still be waiting here.