🎓 A1Learner
🔍

Rust Higher-Order Functions

A higher-order function is a function that takes a function as input, returns a function, or does both.

map hands your closure each item

map is a higher-order function: it receives your closure and decides when to call it — once per item:

let doubled: Vec<i32> = [1, 2, 3].iter().map(|n| n * 2).collect();
println!("{doubled:?}");

Option is full of them too

map, and_then, unwrap_or_else, any and find all take closures — on Option just as on iterators:

let name: Option<&str> = Some("ada");
let shout = name.map(|s| s.to_uppercase());
println!("{shout:?}");
let missing: Option<i32> = None;
println!("{}", missing.unwrap_or_else(|| 42));

The same job in two styles

A loop with an accumulator can do the job. So can a chain of named steps. The imperative and functional styles state the same job:

let mut acc = 0;
for n in 1..=4 {
    acc += n;
}
let total: i32 = (1..=4).sum();
println!("loop = {acc} chain = {total}");

A chain reads in the order it runs

Read the chain in order: keep the even numbers, square each one, then gather what is left:

let kept: Vec<i32> = (1..=10)
    .filter(|n| n % 2 == 0)
    .map(|n| n * n)
    .collect();
println!("{kept:?}");

Example

fn is_odd(n: u32) -> bool {
    n % 2 == 1
}
fn main() {
    let upper = 100;
    let mut acc = 0;
    for n in 0.. {
        let squared = n * n;
        if squared >= upper {
            break;
        }
        if is_odd(squared) {
            acc += n;
        }
    }
    println!("imperative style: {acc}");
    let total: u32 = (0..)
        .take_while(|&n| n * n < upper)
        .filter(|&n| is_odd(n * n))
        .sum();
    println!("functional style: {total}");
}

Key points

  • A function that returns a closure, like the counter factory in the last lesson, is also higher-order
  • The chain still compiles down to a tight loop.
  • No list of closures is built and run later.
  • A plain function takes values like numbers and gives values back.
  • A higher-order function works with functions as inputs or outputs.

In this example, the job is to add up certain numbers. Their squares must be odd and below 100. They are 1, 3, 5, 7 and 9, which total 25. The first half does it the step-by-step way. A loop squares each number and breaks at 100. It adds the number when its square is odd. The second half says the same job as a chain. take_while keeps numbers while the square is below 100. filter keeps those with odd squares. And sum adds them. Both halves print 25. take_while, filter and sum do the looping for you. Each step is a higher-order function. Each one calls the closure you handed it.

Note

Higher-order functions plus lazy iterators give Rust its functional flavour.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What makes a function higher-order?