← Back to Rust Course | Chapter 4: Functions | Lesson 5 of 6

Higher-Order Functions

A higher-order function is one that can take another function or closure as its input, or hand one back as its answer.

Passing a Closure as a Parameter

A function can accept a closure as a parameter by specifying a trait bound like Fn(i32) -> i32, which describes any callable that takes an i32 and returns an i32.

Example: Passing a Closure as a Parameter

markup
fn apply_twice<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(f(x))
}

fn main() {
    let result = apply_twice(|n| n + 3, 10);
    println!("{}", result);
}

Using map with a Closure

The standard library's .map() method on iterators is a higher-order function: it takes a closure and applies it to every element, producing a new iterator of transformed values.

Example: Using map with a Closure

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

Returning a Closure

Functions can also return closures, typically boxed behind Box<dyn Fn(...) -> ...> since closures have unique, unnamed types that need to be captured in a trait object to return.

Example: Returning a Closure

markup
fn make_adder(amount: i32) -> Box<dyn Fn(i32) -> i32> {
    Box::new(move |x| x + amount)
}

fn main() {
    let add_five = make_adder(5);
    println!("{}", add_five(10));
}

Passing a Named Function Instead of a Closure

Because plain functions and closures without captures share a compatible shape, you can pass a named function directly wherever a matching closure type is expected.

Example: Passing a Named Function Instead of a Closure

markup
fn triple(x: i32) -> i32 {
    x * 3
}

fn apply(f: fn(i32) -> i32, value: i32) -> i32 {
    f(value)
}

fn main() {
    println!("{}", apply(triple, 4));
}
Common Mistakes
  1. Forgetting to specify the closure trait bound (Fn, FnMut, or FnOnce) when writing a function that accepts a closure parameter.
  2. Assuming closures and function pointers are exactly interchangeable in every generic context, when their trait bounds differ subtly.
  3. Overcomplicating simple logic with higher-order functions when a plain loop would be clearer for beginners reading the code.
Chapter Summary
  • A function that accepts a closure or another function as a parameter is called a higher-order function.
  • The Fn trait bound describes a closure that can be called repeatedly without consuming captured variables.
  • Standard library methods like .map() and .filter() are higher-order functions taking closures.
  • Function pointers (fn(i32) -> i32) can also be passed like values, similar to closures.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.