Closures

Внешняя ссылка: https://habr.com/ru/articles/588917/

Статьи в разделе:

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);
    }); //цикл через замыкание итератора
}