Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Closures and Iterators

This chapter is a work in progress.

Closures

Anonymous functions that can capture variables from their environment:

let add = |a, b| a + b;
println(add(2, 3));    // 5

let threshold = 10;
let is_big = |n| n > threshold;    // captures `threshold`
println(is_big(15));   // true

Closures as parameters

Functions can accept closures:

fn apply_twice(f: Fn(i64) -> i64, x: i64) -> i64 {
    f(f(x))
}

let double = |n| n * 2;
println(apply_twice(double, 3));    // 12

Closures and effects

Closures inherit effects from the code they contain. A closure that calls println carries a writes(Stdout) effect. The effect system tracks this through higher-order functions — no surprise side effects hiding in callbacks.

Iterators

Iterators let you process sequences lazily:

let numbers = [1, 2, 3, 4, 5];

let doubled = numbers
    .iter()
    .map(|n| n * 2)
    .filter(|n| n > 4)
    .collect();

// doubled = [6, 8, 10]

Iterators work the same over effectful sources. io.lines(), fs.read_lines(path), and future channel/consumer adaptors return impl Iterator too — the source's effects (reads(Stdin), blocks, receives(Kafka), …) flow through map / filter / take into the enclosing function's effect row. One trait, one combinator library; no separate Stream type.

Common iterator methods

items.map(|x| transform(x))       // transform each element
items.filter(|x| predicate(x))    // keep elements that match
items.fold(init, |acc, x| ...)    // reduce to a single value
items.any(|x| x > 10)             // true if any element matches
items.all(|x| x > 0)              // true if all elements match
items.enumerate()                  // pairs of (index, value)
items.zip(other)                   // pairs from two iterators
items.take(n)                      // first n elements
items.skip(n)                      // skip first n elements

The pipe operator with iterators

The pipe operator |> chains transformations naturally:

let result = data
    |> parse
    |> validate
    |> transform;