Closures
Closure is a function-like construct that can capture variables from its surrounding environment. Closures are lightweight and flexible, enabling you to write concise code that can encapsulate context from where they are defined.
The basic syntax of a closure in Rust is:
|parameters| expression_or_blockAnonymous: Closures do not have a name and are often written inline.
Environment Capturing: Closures can capture values from the scope in which they’re defined.
Traits:
Fn: Used for closures that do not modify the captured variables.FnMut: Used for closures that modify the captured variables.FnOnce: Used for closures that take ownership of captured variables.
Examples
Basic Closure
fn main() {
let add = |x, y| x + y; // A closure that adds two numbers
println!("Sum: {}", add(1, 2)); // 3
}Capturing Environment
Closures are inherently flexible and will do what the functionality requires to make the closure work without annotation. This allows capturing to flexibly adapt to the use case, sometimes moving and sometimes borrowing. Closures can capture variables:
by reference:
&Tby mutable reference:
&mut Tby value:
T
By Reference
By Mutable Reference
If we uncomment the line
let _reborrow = &count;we will get this following compile error because we already borrow it in the closure call below it.But if we remove the second call to the closure it will work fine because we already done with the closure hence the
countis not being borrowed.
By Value
If we uncomment the second call to
consume()closure we will get compile error below because we move/drop the variablemovable.But if we don't move/drop the variable
moveableit will work just fine.
Closure Traits
Fn
Captures variables by reference.
Can be called multiple times.
Since both
FnMutandFnOnceare supertraits ofFn, any instance of Fn can be used as a parameter where aFnMutorFnOnceis expected.
FnMut
Captures variables by mutable reference.
Can modify the captured variables.
Since
FnOnceis a supertrait ofFnMut, any instance ofFnMutcan be used where aFnOnceis expected, and sinceFnis a subtrait ofFnMut, any instance ofFncan be used whereFnMutis expected.
FnOnce
Consumes captured variables by value.
Can only be called once.
Since both
FnandFnMutare subtraits ofFnOnce, any instance ofFnorFnMutcan be used where aFnOnceis expected.
Best Practices with Closures
Use closures for short, inline logic:
They are perfect for tasks like sorting, filtering, or mapping in collections.
Choose the right trait (Fn, FnMut, FnOnce):
Use
Fnfor read-only operations.Use
FnMutfor modifying state.Use
FnOncefor consuming captured variables.
Leverage type inference:
Avoid specifying parameter types unless necessary for clarity or disambiguation.
Minimize environment capture:
Be mindful of how closures capture variables, especially in performance-critical code.
Reference
Last updated