liveBook · Manning

Closure

As explained in Rust in Action: Systems programming concepts and techniques

A closure is an anonymous callable value that can contain an expression body and capture values from its surrounding scope.

A closure is an anonymous function defined where it is needed. Write its arguments between vertical bars and its body in braces: `|a, b| { a + b }`. Unlike a named function, a closure can use variables from its surrounding scope; this is called capturing them. section 10.1 section 10.2.1

Call a closure

`let a = 20; let add_to_a = |b| { a + b };` defines a callable value that uses `a` from its surroundings. A closure can also be passed directly to a method: `.map(|field| field.trim())` trims each field during text processing. section 10.3 section 1.5

A closure is not simply a named function with its name removed. Rust represents a closure as a compiler-generated struct that holds any captured variables. It implements `FnOnce` and may also implement `Fn` and `FnMut`. A named function is represented as a function pointer; closures that capture nothing can also be function pointers. section 10.3

Threads make captures especially important. `thread::spawn(|| { ... })` takes a closure, but a spawned thread may outlive the scope that created it. When it needs ownership of surrounding values, write `thread::spawn(move || { ... })`. The `move` keyword moves captured values into the closure rather than leaving the thread dependent on the parent scope. section 10.2.1

Listing 10.1 Defining two functions and checking the result
fn add(a: i32, b: i32) -> i32 {
  a + b
}
 
fn main() {
  let lambda_add = |a,b| { a + b };
 
 assert_eq!(add(4,5), lambda_add(4,5));
}

Compare a named addition function with an inline closure that produces the same result. section 10.1

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains syntax, captures, ownership moves, and compiler-generated closure structs; stops short of implementing concurrency libraries.
Examples
Compares addition as a named function and closure, shows a captured variable, and illustrates a thread-spawn borrow error.
What it assumes
Assumes familiarity with functions and local variables while teaching vertical-bar syntax and captures.
What you can do after
Apply closures via `.map()` and `std::thread::spawn()`, using `move` when spawned work needs ownership of captured values.
How it connects
Connects closures to higher-order programming, threads, ownership, and function pointers.

Also explained in

Compare how 20 books explain closure →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.