Closures
Внешняя ссылка: https://habr.com/ru/articles/588917/
Статьи в разделе:
- Fold
Fold Сlosure
Closure
Замыкания - анонимные функции. Их можно присвоить переменным и вызывать. Это также функция, которая ссылается на свободные переменные в своей области видимости. Базовое использование:
let add_one = |x: i32| -> i32 { x + 1 };
println!("Add one to 5 = {}", add_one(5)); // Add one to 5 = 6
let add_two = |x| x + 2;
println!("Add two to 5 = {}", add_two(5)); // Add two to 5 = 7
let add = |a, b| a + b;
println!("Sum of 5 and 6 = {}", add(5, 6)); // Sum of 5 and 6 = 11
let just_number = || 42;
println!("Answer to all: {}", just_number()); // Answer to all: 42
В отличие от функций, замыкания могут использовать переменные вне своего блока:
(0..3).for_each(|x| {println!("map i = {}", x * 2);});
let factor = 2;
let multiplier = |x| x * factor;
println!("{}", multiplier(5)); // 10
println!("Factor: {factor}"); // factor ещё доступен тут
move
Ключ move перемещает переменную в замыкание:
let greet = move || {
println!("Hello, {}!", name);
};
greet();
// println!("{name}"); даст ошибку
Это нужно для того, чтобы замыкание получило владение данным и пережило scope, в котором оно было объявлено.
Работа с итераторами
.map(<closure>) передаёт владение элементами итератора замыканию, чтобы их можно было трансформировать в другие элементы, которые далее возвращает замыкание.
.filter(<closure>) возвращает оригинальные элементы, когда предикат замыкания возвращает true. Таким образом, отдавать владение элементами замыканию нельзя, и нужно передавать по ссылке.
let x2: Vec<i32> = nums.iter().map(|x| x * 2).collect();
println!("x2 = {x2:?}"); // x2 = [2, 4, 6, 8, 10]
let evens: Vec<&i32> = nums.iter().filter(|&x| x % 2 == 0).collect();
println!("Evens = {evens:?}"); // Evens = [2, 4]
let even_sum: i32 = (0..=10).filter(|n| *n % 2 == 0).sum()
2 в 1 = filter_map()
Можно вернуть элементы, когда предикат значения true, и сразу же их трансформировать. На вход он принимает замыкание, возвращающее Option<T>:
- Если на выходе
Some(value), значение включается в результат; - Если замыкание возвращает
None, элемент исключается фильтром.
let numbers = vec!["1", "2", "abc", "4"];
// Раздельно: filter() и потом map()
let result: Vec<i32> = numbers
.iter()
.filter(|s| s.parse::<i32>().is_ok()) // фильтровать цифры
.map(|s| s.parse::<i32>().unwrap()) // Перевести их в int
.collect();
// Result: [1, 2, 4]
// Вместе: filter_map()
let result: Vec<i32> = numbers
.iter()
.filter_map(|s| s.parse::<i32>().ok()) // фильтр и перевод в 1 шаг
.collect();
// Result: [1, 2, 4]
Вложенные замыкания map()
let a = (0..=3).map(|x| x * 2).map(|y| y - 1);
// первая итерация map(): 2, 4, 6
// вторая итерация map(): 1, 3, 5
for i in a {
println!("{i}");
}All
Замыкание all возвращает True, если все элементы в замыкании соответствуют условию.
let a: Vec<i32> = vec![1, 2, 3, 4];
print!("{}\n", a.into_iter().all(|x| x > 1)); // false
Для пустого вектора замыкание all вернёт True:
let a: Vec<i32> = vec![];
print!("{}\n", a.into_iter().all(|x| x > 1)); // true
Цикл через замыкание vs for
use std::collections::HashMap;
pub fn main() {
let num_vec = vec![1, 2, 1, 3, 5, 2, 1, 4, 6];
let mut number_count: HashMap<i32, i32> = HashMap::new();
for key in num_vec {
*number_count.entry(key).or_default() += 1;
}
/* for (k, v) in number_count {
print!("{} -> {}; ", k, v);
} */
number_count.iter().for_each(|(k, v)| {
print!("{} -> {}; ", k, v);
}); //цикл через замыкание итератора
}