12.4 Working with Closures
12.4.1 Using Closures with Iterator Methods
Closures are often used with iterator methods like map
, filter
, and for_each
.
Example: Using filter
with a Closure
#![allow(unused)] fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; let even_numbers: Vec<_> = numbers.into_iter().filter(|x| x % 2 == 0).collect(); println!("{:?}", even_numbers); // Output: [2, 4, 6] }
- The closure
|x| x % 2 == 0
filters out even numbers. - Note: Iterators are discussed in detail in the next chapter.
12.4.2 Sorting Collections with Closures
Closures can be used to define custom sorting behavior using the sort_by_key
method.
Example: Sorting Structs by a Field
#[derive(Debug)] struct Person { name: String, age: u32, } fn main() { let mut people = vec![ Person { name: "Alice".to_string(), age: 30 }, Person { name: "Bob".to_string(), age: 25 }, Person { name: "Charlie".to_string(), age: 35 }, ]; people.sort_by_key(|person| person.age); println!("{:?}", people); }
- The closure
|person| person.age
extracts theage
field for sorting. sort_by_key
is cleaner and easier to understand thansort_by
.- The closure borrows
person
immutably.
12.4.3 Using Closures with unwrap_or_else
Closures are used in methods like unwrap_or_else
to provide lazy evaluation of default values.
Example:
#![allow(unused)] fn main() { let config: Option<String> = None; let config_value = config.unwrap_or_else(|| { println!("Using default configuration"); "default_config".to_string() }); println!("Config: {}", config_value); }
- The closure is called only if
config
isNone
. - Allows for computation of the default value only when necessary.