Fold fold используется для превращения множества в 1 значение.
Базовый синтаксис fn fold < B , F > ( self , init : B , f : F ) -> B
where
F : FnMut ( B , Self ::Item ) -> B , init: исходное значение счётчика;f: замыкание, которое тоже принимает 2 аргумента: счётчик и объект. Замыкание возвращает счётчик.Как работает fold() преобразовывает каждый элемент по цепочке :
Начинает со значения init в счётчике; Для каждого элемента применяет замыкание f(accumulator, element); Возвращает финальное значение счётчика после обработки всех элементов.
Наглядно по шагам: fold ( init , | acc , x | f ( acc , x ))
// Шаг 1: acc = init
// Шаг 2: acc = f(init, item1)
// Шаг 3: acc = f(acc, item2)
// Шаг 4: acc = f(acc, item3)
// ...
// Возврат финального acc
Сумма чисел: let numbers = vec! [ 1 , 2 , 3 , 4 , 5 ];
let sum = numbers . iter (). fold ( 0 , | acc , & x | acc + x );
println! ( "Sum: {} " , sum ); // 15
// По шагам:
// acc = 0
// acc = 0 + 1 = 1
// acc = 1 + 2 = 3
// acc = 3 + 3 = 6
// acc = 6 + 4 = 10
// acc = 10 + 5 = 15
// код выше можно заменить на sum()
Произведение чисел: let numbers = vec! [ 1 , 2 , 3 , 4 , 5 ];
let product = numbers . iter (). fold ( 1 , | acc , & x | acc * x );
println! ( "Product: {} " , product ); // 120
// код выше можно заменить на product()
Нахождение максимального значения let numbers = vec! [ 3 , 1 , 4 , 1 , 5 , 9 , 2 ];
let max = numbers . iter (). fold ( i32 ::MIN , | acc , & x | acc . max ( x ));
println! ( "Max: {} " , max ); // 9
Соединение (конкатенация) строк Счётчик у fold необязательно числовой, можно использовать, например, String:
fn hello_world_concat () {
let words = vec! [ "hello" , "world" , "rust" ];
let sentence = words . iter (). fold ( String ::new (), | acc , & word | {
if acc . is_empty () {
word . to_string ()
} else {
acc + " " + word
}});
println! ( "Sentence: ' {} '" , sentence ); // "hello world rust"
}
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 },
)}
fn main () {
let song = giant_grunts ( 'F' );
println! ( " {song:?} " ); // "FeeFiFoFum"
} Разделение на чётные и нечётные let numbers = vec! [ 1 , 2 , 3 , 4 , 5 ];
let result = numbers . iter (). fold (
( Vec ::new (), Vec ::new ()), // (evens, odds)
| ( mut evens , mut odds ), & x | {
if x % 2 == 0 {
evens . push ( x );
} else {
odds . push ( x );
}
( evens , odds )
}
);
println! ( "Evens: {:?} , Odds: {:?} " , result . 0 , result . 1 );
// Evens: [2, 4], Odds: [1, 3, 5]
Получение частоты символов в тексте: Создаёт HashMap . Заменяет итератор counts() из библиотеки itertools :
use std ::collections ::HashMap ;
pub fn first_non_repeating ( s : & str ) -> Option < HashMap < char , i32 >> {
let char_frequency = s . chars (). fold ( HashMap ::new (), | mut acc , c | {
* acc . entry ( c ). or_insert ( 0 ) += 1 ;
acc
});
Some ( char_frequency )
}
fn main () {
println! ( "Letter frequency: {:?} " , first_non_repeating ( "stress" ));
} // Letter frequency: Some({'e': 1, 'r': 1, 's': 3, 't': 1})
arr.chars(): Creates an iterator over references to the array elements (chars).fold(HashMap::new(), ...): Reduces the iterator to a single value (HashMap)HashMap::new(): Initial empty HashMap (the starting accumulator)|mut acc, x|: Closure with parameters:mut acc: Mutable accumulator (the HashMap being built)c: Current element from the iterator (reference to a string like &"abc")По шагам:
acc.entry(x) : Calls entry() on the HashMap with key cThis returns an Entry enum (Occupied or Vacant) for the key c .or_insert(0) : Entry API methodIf key c doesn’t exist in the map: inserts value 0 and returns mutable reference to it If key c already exists: returns mutable reference to the existing value *... += 1 : Dereferences and incrementsThe or_insert(0) returns &mut i32 (mutable reference to integer) * dereferences to get the actual integer value+= 1 increments the count by 1Реализация других методов Реализация map() let numbers = vec! [ 1 , 2 , 3 , 4 , 5 ];
let doubled : Vec < i32 > = numbers . iter (). fold ( Vec ::new (), | mut acc , & x | {
acc . push ( x * 2 );
acc });
println! ( "Doubled: {:?} " , doubled ); // [2, 4, 6, 8, 10]
Реализация filter() let numbers = vec! [ 1 , 2 , 3 , 4 , 5 , 6 ];
let evens : Vec < i32 > = numbers . iter (). fold ( Vec ::new (), | mut acc , & x | {
if x % 2 == 0 {
acc . push ( x ); }
acc });
println! ( "Evens: {:?} " , evens ); // [2, 4, 6]
Вариация try_fold() От fold() отличается тем, что прерывает выполнение и возвращает Result(Err):
let strings = [ "1" , "2" , "3" , "4" , "5" ];
// перевести строки в числа и суммировать их
let sum : Result < i32 , _ > = strings
. iter ()
. try_fold ( 0 , | acc , & s | match s . parse ::< i32 > () {
Ok ( num ) => Ok ( acc + num ),
Err ( e ) => Err ( e ),
});
match sum {
Ok ( total ) => println! ( "Total: {} " , total ), // 15
Err ( e ) => println! ( "Parse error: {} " , e ), }