# Chapter 13.1 (Only) - Functional Language Features: Iterators and Closures ## Motivation for Closure ``` rust fn generate_workout(intensity: u32, random_number: u32) { if intensity < 25 { println!( "Today, do {} pushups!", simulated_expensive_calculation(intensity) ); println!( "Next, do {} situps!", simulated_expensive_calculation(intensity) ); } else { if random_number == 3 { println!("Take a break today! Remember to stay hydrated!"); } else { println!( "Today, run for {} minutes!", simulated_expensive_calculation(intensity) ); } } } ``` Cons: In the above function, you call `simulated_expensive_calculation` twice in the first if block. Let's improve it: ``` rust fn generate_workout(intensity: u32, random_number: u32) { let expensive_result = simulated_expensive_calculation(intensity); if intensity < 25 { println!( "Today, do {} pushups!", expensive_result ); println!( "Next, do {} situps!", expensive_result ); } else { if random_number == 3 { println!("Take a break today! Remember to stay hydrated!"); } else { println!( "Today, run for {} minutes!", expensive_result ); } } } ``` In the above implementation, the expensive computation is computed only once. Unfortantely for cases where `intensity >= 25 && random_number == 3`, we have to perform the expensive computation although it isn't required. Let's use closures here. To define a closure, we start with a pair of vertical pipes (`|`), inside which we specify the parameters to the closure: ``` rust fn generate_workout(intensity: u32, random_number: u32) { let expensive_closure = |num| { println!("calculating slowly..."); thread::sleep(Duration::from_secs(2)); num }; if intensity < 25 { println!( "Today, do {} pushups!", expensive_closure(intensity) ); println!( "Next, do {} situps!", expensive_closure(intensity) ); } else { if random_number == 3 { println!("Take a break today! Remember to stay hydrated!"); } else { println!( "Today, run for {} minutes!", expensive_closure(intensity) ); } } } ``` However the above implementation has the same problem of the first variant. We could fix this problem by creating a variable local to that if block to hold the result of calling the closure, but closures provide us with another solution. Let's learn something more before finding out solution to the above problem. ## Closure Type Inference and Annotation Closures don’t require you to annotate the types of the parameters or the return value like `fn` functions do. But we can add type annotations if we want to increase explicitness and clarity at the cost of being more verbose than is strictly necessary. ``` rust let expensive_closure = |num: u32| -> u32 { println!("calculating slowly..."); thread::sleep(Duration::from_secs(2)); num }; ``` Closure definitions will have one concrete type inferred for each of their parameters and for their return value. The following code won't compile: ``` rust let example_closure = |x| x; let s = example_closure(String::from("hello")); let n = example_closure(5); ``` ## Storing Closures Using Generic Parameters and the `Fn` Traits One solution to the above function `generate_workout` is to save the result of the expensive closure in a variable for reuse and use the variable in each place we need the result. To make a struct that holds a closure, we need to specify the type of the closure, because a struct definition needs to know the types of each of its fields. Each closure instance has its own unique anonymous type: that is, even if two closures have the same signature, their types are still considered different. The `Fn` traits are provided by the standard library. All closures implement at least one of the traits: `Fn`, `FnMut`, or `FnOnce`. ``` rust struct Cacher<T> where T: Fn(u32) -> u32 { calculation: T, value: Option<u32>, } ``` The `Cacher` struct has a `calculation` field of the generic type `T`. The trait bounds on T specify that it’s a closure by using the Fn trait. Any closure we want to store in the `calculation` field must have one `u32` parameter (specified within the parentheses after `Fn`) and must return a `u32` (specified after the `->`). ``` rust impl<T> Cacher<T> where T: Fn(u32) -> u32 { fn new(calculation: T) -> Cacher<T> { Cacher { calculation, value: None, } } fn value(&mut self, arg: u32) -> u32 { match self.value { Some(v) => v, None => { let v = (self.calculation)(arg); self.value = Some(v); v }, } } } ``` And now the implementation: ``` rust fn generate_workout(intensity: u32, random_number: u32) { let mut expensive_result = Cacher::new(|num| { println!("calculating slowly..."); thread::sleep(Duration::from_secs(2)); num }); if intensity < 25 { println!( "Today, do {} pushups!", expensive_result.value(intensity) ); println!( "Next, do {} situps!", expensive_result.value(intensity) ); } else { if random_number == 3 { println!("Take a break today! Remember to stay hydrated!"); } else { println!( "Today, run for {} minutes!", expensive_result.value(intensity) ); } } } ``` The above implementation doesn't suffer from any of the above cons discussed above. The function is computed only once when required. But there is a problem with the above implementation. The code will fail (obviously) for this scenario: ``` rust #[test] fn call_with_different_values() { let mut c = Cacher::new(|a| a); let v1 = c.value(1); let v2 = c.value(2); assert_eq!(v2, 2); } ``` This problem can be fixed by changing the struct implementation to store the key and value mapping in a hashmap. ## Capturing the Environment with Closures In the above example, we used closures as inline anonymous functions. We can also use it to capture their environment and access variables from the scope in which they're defined. ``` rust fn main() { let x = 4; let equal_to_x = |z| z == x; let y = 4; assert!(equal_to_x(y)); } ``` whereas something like this will result in an compile error: ``` rust fn main() { let x = 4; fn equal_to_x(z: i32) -> bool { z == x } let y = 4; assert!(equal_to_x(y)); } ``` Closures can capture values from their environment in three ways, which directly map to the three ways a function can take a parameter: taking ownership, borrowing mutably, and borrowing immutably. These are encoded in the three `Fn` traits as follows: * `FnOnce` consumes the variables it captures from its enclosing scope, known as the closure’s environment. To consume the captured variables, the closure must take ownership of these variables and move them into the closure when it is defined. The `Once` part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can be called only once. * `FnMut` can change the environment because it mutably borrows values. * `Fn` borrows values from the environment immutably. When you create a closure, Rust infers which trait to use based on how the closure uses the values from the environment. All closures implement `FnOnce` because they can all be called `at least` once. Closures that don’t move the captured variables also implement `FnMut`, and closures that don’t need mutable access to the captured variables also implement `Fn`. [Reddit thread on usecase of FnOnce](https://www.reddit.com/r/rust/comments/2s7l0m/whats_the_usecase_for_fnonce/) If you want to force the closure to take ownership of the values it uses in the environment, you can use the `move` keyword before the parameter list. This technique is mostly useful when passing a closure to a new thread to move the data so it’s owned by the new thread. Example: ``` rust fn main() { let x = vec![1, 2, 3]; let equal_to_x = move |z| z == x; println!("can't use x here: {:?}", x); let y = vec![1, 2, 3]; assert!(equal_to_x(y)); } ``` The above program will result in compile error till you have the printlin statement in the code.