What Are Closures?
Closures are similar to regular functions but with the added ability to automatically capture variables from their defining scope. This means that closures can access variables defined outside their immediate scope without requiring explicit parameter passing.

Basic Syntax
In Rust, closures feature a compact and expressive syntax. Below is an example of a simple closure that adds two numbers. Although Rust often infers parameter and return types, explicit annotations can help clarify the developer’s intent (as highlighted by the Rust Analyzer extension).- The closure is defined using vertical pipes (
| |) to enclose its parameters. - The arrow (
-> i32) indicates that the closure returns an integer. - The closure invocation with values 2 and 3 then prints the result, 5.
Capturing the Environment
One of the key features of closures in Rust is their ability to capture variables from the surrounding environment. This enables the closure to maintain context without explicitly passing all dependencies.Closures can capture variables by value, by reference, or by mutable reference. Rust automatically determines the most appropriate capture semantics based on how the closure is used.
num from its scope:
num is captured automatically. Depending on how the closure interacts with the variable, the capture method may be by value, by reference, or by mutable reference.
Surrounding Environment
The “surrounding environment” of a closure comprises any variables that are in scope when the closure is defined. For instance, a global static variable can be accessed directly by a closure without requiring capture:GLOBAL_NUM has a static lifetime, it remains accessible throughout the program’s execution.
Capturing by Mutable Reference
Closures can also capture variables by mutable reference, which allows them to modify the captured variables. The example below demonstrates this capability:Closure Traits
Closures automatically implement one of three traits based on their interaction with captured variables:- Fn: For closures that capture variables immutably (read-only).
- FnMut: For closures that capture variables mutably (can modify).
- FnOnce: For closures that capture variables by taking ownership (the variables can be used only once).
Using the Fn Trait
The following example demonstrates how to create a function that accepts a closure implementing theFn trait:
Using the FnMut Trait
When a closure needs to modify an external variable, it implements theFnMut trait. Consider this example:
Using the FnOnce Trait
Closures that take ownership of captured variables using themove keyword implement the FnOnce trait. Once a variable is moved into the closure, it is no longer accessible outside of it:
Returning Closures from Functions
Returning closures from functions in Rust requires using either trait objects or generics because closures do not have a fixed type. A common solution is to return a boxed closure:Box<dyn Fn(i32) -> i32>, allowing dynamic dispatch at runtime.
Best Practices with Closures
When using closures in Rust, consider the following best practices:- Minimize the Captured Environment: Capture only what is necessary to reduce overhead.
- Choose the Right Trait: Select between
Fn,FnMut, orFnOncebased on whether the closure reads, modifies, or takes ownership of its captured variables. - Be Aware of Lifetime Issues: Understand how closures interact with Rust’s lifetime system to avoid borrowing conflicts and ownership errors.

Learn more about Rust and closures by exploring the Rust Programming Language and Rust by Example.