fn / Closures (|x| x+1)
Functions in Rust are defined with the fn keyword. Closures are written in the form |args| expression and can capture variables from the surrounding scope. Closures can be passed as function arguments or assigned to variables.
Syntax
// A regular function definition. Parameter types and return type must be specified explicitly.
fn add(a: i32, b: i32) -> i32 {
a + b // The last expression is the return value (no semicolon).
}
// A closure (anonymous function). Types can be omitted thanks to type inference.
let add = |a, b| a + b;
let double = |x: i32| -> i32 { x * 2 };
// Capturing a variable from the outer scope (by borrow).
let offset = 10;
let add_offset = |x| x + offset; // Borrows offset.
// move closure: takes ownership of captured variables.
let name = String::from("Rust");
let greet = move || println!("Hello, {}", name); // Ownership of name is moved into the closure.
// A function that accepts a closure as an argument (using the Fn trait).
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
Functions and Closures Reference
| Syntax / Trait | Description |
|---|---|
| fn name(args) -> Type { } | Defines a regular function. |
| |args| expression | Defines a closure (anonymous function). Types are inferred. |
| |args: Type| -> Type { } | A closure with explicit type annotations. |
| move |args| expression | Captures variables from the outer scope by moving their ownership. |
| Fn(&self) | A closure that captures by immutable reference. |
| FnMut(&mut self) | A closure that captures by mutable reference (can modify captured state). |
| FnOnce(self) | A closure that takes ownership of captured variables (can only be called once). |
| fn(Type) -> Type | A function pointer type (distinct from closures). |
| impl Fn(Type) -> Type | Used as the return type of a function that returns a closure. |
Sample Code
// Higher-order function: accepts a function as an argument.
fn apply<F>(f: F, values: &[i32]) -> Vec<i32>
where
F: Fn(i32) -> i32,
{
values.iter().map(|&x| f(x)).collect()
}
// A function that returns a closure.
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n // Moves ownership of n into the closure.
}
fn main() {
// A regular function.
fn square(x: i32) -> i32 {
x * x
}
println!("square(5) = {}", square(5));
// Basic closure usage.
let double = |x| x * 2;
let add_one = |x: i32| -> i32 { x + 1 };
println!("double(4) = {}", double(4));
println!("add_one(9) = {}", add_one(9));
// Capturing a variable from the outer scope.
let threshold = 5;
let is_big = |x| x > threshold; // Borrows threshold.
println!("is_big(7) = {}", is_big(7));
println!("is_big(3) = {}", is_big(3));
// Passing a closure to a higher-order function.
let nums = vec![1, 2, 3, 4, 5];
let doubled = apply(|x| x * 2, &nums);
println!("doubled: {:?}", doubled);
let squared = apply(square, &nums); // Regular functions can be passed too.
println!("squared: {:?}", squared);
// A function that returns a closure (closure factory).
let add5 = make_adder(5);
let add10 = make_adder(10);
println!("add5(3) = {}", add5(3));
println!("add10(3) = {}", add10(3));
// FnMut: a closure that modifies its captured state.
let mut counter = 0;
let mut increment = || {
counter += 1;
counter
};
println!("count: {}", increment()); // 1
println!("count: {}", increment()); // 2
println!("count: {}", increment()); // 3
}
Overview
Rust closures automatically implement one of the Fn, FnMut, or FnOnce traits depending on how they capture variables from the surrounding scope. If a closure only reads captured variables, it implements Fn; if it modifies them, FnMut; if it takes ownership, FnOnce.
When passing a closure to another thread or a context that outlives the current scope, the move keyword is required. Using move transfers ownership of all captured variables into the closure.
While a closure holds a mutable reference to a captured variable, that variable cannot be used elsewhere at the same time. The borrow checker rules apply.
For detailed information on the closure traits (Fn / FnMut / FnOnce), see 'Fn / FnMut / FnOnce Traits'.
If you find any errors or copyright issues, please contact us.