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