Functional Language Features Iterators and Closures

Closures: Anonymous Functions that Capture Their Environment

闭包:可以捕获其所在环境的匿名函数

闭包的定义

1
2
3
|parameters: type, ...| -> type {
code
}

参数和返回值的类型可以不用显示标注,编译器会自动推断

可以将闭包赋值给变量调用

1
2
3
let f = |num: i32| {
num
};

如何让 struct 持有闭包

需要泛型和 Fn Trait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct Cacher<T> 
where
T: Fn(i32) -> i32,// 参数和返回值
{
cal: T,
value: Option<i32>,
}

impl<T> Cacher<T>
where
T: Fn(i32) -> i32,
{
fn new(x: T) -> Cacher<T> {
Cacher {
cal: x,
value: None,
}
}

fn value(&mut self, arg: i32) -> i32 {
match self.value {
Some(x) => x,
None => {
let v = (self.cal)(arg);
self.value = Some(v);
v
}
}
}
}

使用闭包捕获环境

直接使用函数不能捕获外界的变量

1
2
3
4
5
6
// can't capture dynamic environment in a fn item
let x = 5;
fn f(y: i32) -> i32 {
x
}
println!("{}", f(x));

使用闭包捕获外界的值

1
2
3
4
5
let x = 5;
let f = |num: i32| -> i32 {
x
};
println!("{}", f(x));

闭包从所在环境捕获值的方式

  • FnOnce 取得所有权
  • FnMut 可变借用
  • Fn 不可变借用

move 关键字,强制闭包获得它使用环境值的所有权

1
2
3
4
5
6
let x = String::from("2024");
let f = move || { // move
x == String::from("2024")
};
println!("{}", x);
// value borrowed here after move

Processing a Series of Items with Iterators

迭代器模式:对一系列项执行某些任务

迭代器负责:遍历每个项,确定序列(遍历)何时完成

rust 的迭代器

懒惰的: 除非调用消费迭代器的方法,否则迭代器本身没有任何效果

1
2
3
4
5
let v = vec![1, 2, 3];
let v_iter = v.iter();
for x in v_iter {
println!("{}", x);
}

iterator trait

所有 迭代器都实现了 iterator trait

iterator trait 仅要求实现一个方法 next

next 每次返回迭代器中的一项,返回结果包裹在 Some, 结束返回 None

迭代器使用

  • iter : 在不可变引用上创建迭代器
  • into_iter : 创建的迭代器会获得所有权
  • iter_mut : 迭代可变的引用

map 接受一个闭包,闭包作用于每个元素,产生一个新的迭代器

collect 消耗型适配器,把结果收集到一个集合类型中

1
2
3
4
let v = vec![1, 2, 3];
let v_iter = v.iter();
let v1: Vec<_> = v_iter.map(|x| x + 1).collect();
assert_eq!(vec![2, 3, 4], v1);

filter 接受闭包,闭包返回 bool 类型,当返回 true 时,产生的迭代器就会包含该元素

1
2
3
4
let v = vec![1, 2, 3, 5, 6];
let v_iter = v.into_iter(); // 获取所有权
let v1: Vec<_> = v_iter.filter(|x| x % 3 == 0).collect();
assert_eq!(vec![3, 6], v1);

自定义迭代器,实现 next

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Counter {
count: u32,
}

impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}

Comparing Performance: Loops vs. Iterators

迭代器与循环效率比较

迭代器效率更高

迭代器是 Rust 的 零成本抽象(zero-cost abstractions)之一,它意味着抽象并不会引入运行时开销