Closures

Rust also has support for closures. Closures are like functions but have more information of the environment or scope in which they are declared. While functions have names associated with them, closures are defined without a name, but they can be assigned to a variable. Another advantage of Rust's type inference is that, in most cases, you can specify parameters for a closure without their type. Here's the the simplest possible closure: let my_closure = || ();. We just defined a no-parameter closure that does nothing. We can call this by invoking my_closure(), just like functions. The two vertical bars || hold the parameters for the closure (if any), such as |a, b|. Specifying the types of parameters (|a: u32|) is sometimes required when Rust cannot figure out the proper types. Like functions, closures can also be stored in variables and invoked later or passed to other functions. The body of the closure, however, can either have a single line expression or a pair of braces for multi-line expressions. A more involved closure would be as follows:

// closures.rs

fn main() {
let doubler = |x| x * 2;
let value = 5;
let twice = doubler(value);
println!("{} doubled is {}", value, twice);

let big_closure = |b, c| {
let z = b + c;
z * twice
};

let some_number = big_closure(1, 2);
println!("Result from closure: {}", some_number);
}

In the preceding code, we have defined two closures: doubler and big_closure. doubler doubles a value given to it; in this case, it is passed value from the parent scope or environment, that is, the function main. Similarly, in big_closure, we use the variable twice from its environment. This closure has multi-line expressions within braces and needs to end with a semi-colon to allow us to assign it to the  big_closure variable. Later, we call big_closure, passing in 1, 2, and print some_number.

The major use case for closures are as parameters to higher-order functions. A higher-order function is a function that takes another function or closure as its argument. For example, the thread::spawn function from the standard library takes in a closure where you can write code you want to run in another thread. Another example where closures provide a convenient abstraction is when you have a function that operates on collection such as Vec and you want to filter the items based on some condition. Rust's Iterator trait has a method called filter, which takes in a closure as an argument. This closure is defined by the user and it returns either true or false, depending on how the user wants to filter the items in the collection. We'll get more in-depth with closures in Chapter 7, Advanced Concepts.