🎓 A1Learner
🔍

Rust Closures Basics

A closure is a small unnamed function that a program can save in a variable. A closure can use the values around the place where it is written.

A named function stands alone

A named function sees only its inputs. The bonus inside main is out of triple's reach:

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

fn main() {
    let bonus = 10;
    println!("triple = {}", triple(4));
    println!("bonus waits outside = {}", bonus);
}

A closure uses the room around it

A closure written in the same room can use the room's values. It borrows bonus, so bonus stays usable after the call:

fn main() {
    let bonus = 10;
    let add_bonus = |score: i32| score + bonus;
    println!("with bonus = {}", add_bonus(32));
    println!("bonus still here = {}", bonus);
}

Hand a closure to a method

Many methods ask for a small job in the form of a closure. sort_by_key sorts by whatever its closure hands back:

fn main() {
    let mut words = ["banana", "kiwi", "apple"];
    words.sort_by_key(|w| w.len());
    println!("{:?}", words);
}

move hands the values over

The word move gives the closure the room's values to keep. The old name stops working:

fn main() {
    let greeting = String::from("hello");
    let say = move || println!("{}", greeting);
    say();
    // println!("{}", greeting); // error: greeting was moved into the closure
}

Example

fn main() {
    let limit = 10;
    let over_limit = |n: i32| n > limit;
    let scores = [7, 12, 4, 20];
    let mut big = 0;
    for s in scores {
        if over_limit(s) {
            big += 1;
        }
    }
    println!("scores over {} = {}", limit, big);
    let mut names = ["cy", "ada", "bo"];
    names.sort_by_key(|n| n.len());
    println!("by length = {:?}", names);
}

Key points

  • Unlike a named function, a closure can reach the values in the room where it is written.
  • A closure is written with its inputs between two bars, like |x| x + 1.
  • The types of a closure's inputs are usually guessed from how the closure is used.
  • Use the word move when the closure must own the values it uses.

In this example, over_limit is a closure. It borrows limit from the room around it, so the test n > limit can read the 10. The for loop calls it on each score, and two scores pass. Then sort_by_key receives a second closure. That one hands back each name's length, and the names come out shortest first. Rust Closures, in the Intermediate course, goes deeper from here — how closures capture values, and the traits behind them.

Note

A closure borrows what it uses by default.

The move word turns that borrow into ownership.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

A closure written inside main uses a variable from main. What happens to that variable?