Closures

Closure

  • Замыкания можно присвоить переменным и вызывать;
  • В отличие от функций, замыкания могут использовать переменные вне своего блока.

Map и Filter

.map(<closure>) передаёт владение элементами итератора замыканию, чтобы их можно было трансформировать в другие элементы, которые далее возвращает замыкание.

.filter(<closure>) возвращает оригинальные элементы, когда предикат замыкания возвращает true. Таким образом, отдавать владение элементами замыканию нельзя, и нужно передавать по ссылке.

let a = (0..3).map(|x| x * 2);
for i in a {
    println!("map i = {}", i);
}

let a = (0..3).filter(|&x| x % 2 == 0);
for i in a {
    println!("filter i = {}", i);
}

Fold

Каждая итерация fold принимает 2 аргумента:

  • Исходное значение счётчика;
  • Замыкание, которое тоже принимает 2 аргумента: счётчик и объект. Замыкание возвращает счётчик.

fold используется для превращения множества в 1 значение. Пример для получения суммы всех чётных чисел:

pub fn main() {
    let even_sum = (1..=10).fold(0, |acc, num| if num % 2 == 0 { acc + num } else { acc });
    println!("{even_sum:?}");
}

fold можно часто заменить другими методами. Например, код выше можно заменить на отбор всех чётных числе с помощью filter и их сложение с помощью sum:

(0..=10).filter(|n| *n % 2 == 0).sum()

Наравне с sum также популярны product и collect.

Счётчик у fold необязательно числовой, можно использовать, например, String:

pub fn giant_grunts(initial: char) -> String {
    ["Bee", "Fee", "Gee", "Fi", "Hi", "Fo", "Mo", "Fum", "Tum"].iter().fold(
        String::new(),
        |acc, grunt| if grunt.starts_with(initial) { acc + grunt } else { acc },
    )}

pub fn main() {
    let song = giant_grunts('F');
    println!("{song:?}"); // "FeeFiFoFum" 
}

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