← 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.
Syntax
rust
fn name<F>(f: F) -> ReturnType
where
    F: Fn(ParamType) -> ReturnType,
{
    f(value)
}

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))
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `result`, set to `apply_twice(|n| n + 3, 10)`
    let result = apply_twice(|n| n + 3, 10);
    // Print "{}" to the console, substituting in `result` (with a trailing newline)
    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
// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `numbers`, set to `vec![1, 2, 3]`
    let numbers = vec![1, 2, 3];
    // Declare an immutable variable `doubled` (a `Vec<i32>`), set to `numbers.iter().map(|n| n * 2).collect()`
    let doubled: Vec<i32> = numbers.iter().map(|n| n * 2).collect();
    // Print "{:?}" to the console, substituting in `doubled` (with a trailing newline)
    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
// Define the function `make_adder` taking `amount` and returning a `Box<dyn Fn(i32) -> i32>`
fn make_adder(amount: i32) -> Box<dyn Fn(i32) -> i32> {
    Box::new(move |x| x + amount)
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `add_five`, set to `make_adder(5)`
    let add_five = make_adder(5);
    // Print "{}" to the console, substituting in `add_five(10)` (with a trailing newline)
    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
// Define the function `triple` taking `x` and returning an integer
fn triple(x: i32) -> i32 {
    x * 3
}

// Define the function `apply` taking `f`, `value` and returning an integer
fn apply(f: fn(i32) -> i32, value: i32) -> i32 {
    f(value)
}

// Entry point: execution of the program starts here
fn main() {
    // Print "{}" to the console, substituting in `apply(triple, 4)` (with a trailing newline)
    println!("{}", apply(triple, 4));
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
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.