A closure is an anonymous function that can be:
Stored in a variable.
Passed as an argument.
Returned from a function.
The syntax of a closure is more like an expression. It uses the
vertical bars || to declare the arguments of the closure and then an
expression that uses those arguments to compute a value. Here is a
closure that doubles a value, that we use as a normal function:
{
let double = |x| x * 2;
println!("{}", double(5));
}10
()We can define a function that takes a closure. We use the Fn trait
with the type of the argument and the returned type to describe the
closure type:
fn foo(f: impl Fn(i32) -> i32) {
for i in 0..10 {
print!("{} ", f(i))
}
}Here is the effect of calling foo() with double():
{
let double = |x| x * 2;
foo(double);
}()A function can return a closure as illustrated by the following
example in which we create any closure that multiplies a number by a
factor. The move keyword is compulsory. It tells the compiler that
the closure takes ownership of the factor variable:
fn make_closure(factor: i32) -> impl Fn(i32) -> i32 {
move |x| x * factor
}We call directly the closure returned by the make_closure()
function:
make_closure(3)(10)30Or pass it to another function:
foo(make_closure(5));23.2.1Capturing variables¶
A closure can also capture variables from its scope. Hence the name closure that embeds together a function/expression definition with an environment (i.e.: variables from the scope).
Here the definition of a closure that takes an argument z but also
embeds the variable x from its scope. The evaluation is done as
usual:
{
let x = 4;
let equal_to_x = |z| z == x;
println!("{}", equal_to_x(5));
}0 5 10 15 20 25 30 35 40 45 false
()The capture of a variable by a closure, means the closure borrows the variable. A mutable variable that is captured, cannot be modified as long as the closure is alive:
{
let mut x = 4;
let equal_to_x = |z| z == x;
x = 7;
equal_to_x(7)
}[E0506] Error: cannot assign to `x` because it is borrowed
╭─[ command_9:1:1 ]
│
3 │ let equal_to_x = |z| z == x;
│ ─┬─
│ ╰─── `x` is borrowed here
4 │ x = 7;
│ ──┬──
│ ╰──── `x` is assigned to here but it was already borrowed
│
├─[ command_9:1:1 ]
│
3 │ let equal_to_x = |z| z == x;
│ ┬
│ ╰── borrow occurs due to use in closure
│
5 │ equal_to_x(7)
│ ─────┬────
│ ╰────── borrow later used here
───╯[unused_assignments] Error: value assigned to `x` is never read
╭─[ command_9:1:1 ]
│
4 │ x = 7;
│ ──┬──
│ ╰──── warning: value assigned to `x` is never read
───╯