In Rust, closures (often called lambdas in other languages) are anonymous functions you can save in a variable or pass as an argument. They are very useful for short, inline behavior—especially with collections like vectors.
In this article, we will look at several simple examples of using closures in Rust.
1. Simple Closure (No Parameter)
fn main() {
let greet = || println!("Hello, Rust!");
greet(); // Call the closure
}
Output:
Hello, Rust!
The closure greet takes no arguments and simply prints a message.
2. Closure with Parameters
fn main() {
let add = |a: i32, b: i32| a + b;
println!("3 + 5 = {}", add(3, 5));
}
Output:
3 + 5 = 8
This closure takes two i32 parameters and returns their sum. Note that type annotations are optional if the compiler can infer them.
3. Closure Capturing Variables
fn main() {
let x = 10;
let print_x = || println!("Captured x = {}", x);
print_x();
}
Output:
Captured x = 10
The closure print_x captures the variable x from its environment and prints it.
4. Mutable Capture in Closure
fn main() {
let mut count = 0;
let mut inc = || {
count += 1;
println!("Count: {}", count);
};
inc();
inc();
}
Output:
Count: 1
Count: 2
The closure mutably borrows count and modifies it. Therefore, the closure itself must be marked mut.
5. Passing Closure to a Function
fn apply(func: F)
where
F: Fn(),
{
func();
}
fn main() {
let shout = || println!("Rust is awesome!");
apply(shout);
}
Output:
Rust is awesome!
The function apply takes any closure that implements the Fn trait and executes it.
6. Closure Returning Values
fn main() {
let square = |x: i32| -> i32 {
x * x
};
println!("Square of 4 is {}", square(4));
}
Output:
Square of 4 is 16
Closures can return values just like functions. The return type can be omitted if obvious.
7. Iterator + Closure (Map Example)
fn main() {
let nums = vec![1, 2, 3, 4, 5];
let doubled: Vec = nums.iter().map(|x| x * 2).collect();
println!("Doubled: {:?}", doubled);
}
Output:
Doubled: [2, 4, 6, 8, 10]
The closure inside .map() multiplies each number by 2. This is a very common use case of closures with iterators.
8. Closure as Return Type
fn multiplier(factor: i32) -> impl Fn(i32) -> i32 {
move |x| x * factor
}
fn main() {
let double = multiplier(2);
println!("5 * 2 = {}", double(5));
}
Output:
5 * 2 = 10
The function multiplier returns a closure that multiplies its input by the captured factor. The move keyword is required to move ownership into the closure.
Rust closures are powerful and flexible, allowing you to:
- Capture variables from the environment
- Be passed as arguments to functions
- Be returned from functions
- Work seamlessly with iterators
- They’re an essential part of functional programming in Rust, especially when working with collections.
References:
Happy Learning 🙂