02-迭代器 Iterator
迭代器 Iterator — Rust By Practice
内容来源 · Rust By Practice / Rust 语言实战
原文链接: https://practice-rust.beatai.org/functional-programing/iterator.html
迭代器 Iterator
迭代器模式让我们能依次对序列中的每一项执行操作。迭代器负责遍历每一项的逻辑,并判断序列何时结束。
for 与迭代器
1
2
3
4
5
6
| fn main() {
let v = vec![1, 2, 3];
for x in v {
println!("{}",x)
}
}
|
上面的代码里,你可能把 for 当成简单循环,但它实际上是在遍历迭代器。
默认情况下,for 会对集合调用 into_iter,将其转换为迭代器。因此下面的代码与上面等价:
1
2
3
4
5
6
| fn main() {
let v = vec![1, 2, 3];
for x in v.into_iter() {
println!("{}",x)
}
}
|
- 🌟
1
2
3
4
5
6
7
| /* 使用迭代器重构以下代码 */
fn main() {
let arr = [0; 10];
for i in 0..arr.len() {
println!("{}",arr[i]);
}
}
|
- 🌟 创建迭代器最简单的方式之一是使用区间:
a..b。
1
2
3
4
5
6
7
8
9
| /* 填空 */
fn main() {
let mut v = Vec::new();
for n in __ {
v.push(n);
}
assert_eq!(v.len(), 100);
}
|
next 方法
所有迭代器都实现了标准库中定义的 Iterator trait:
1
2
3
4
5
6
7
| pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 省略了带默认实现的方法
}
|
我们可以直接在迭代器上调用 next 方法。
- 🌟🌟
1
2
3
4
5
6
7
8
| /* 填空并修复错误。尽可能使用两种方式 */
fn main() {
let v1 = vec![1, 2];
assert_eq!(v1.next(), __);
assert_eq!(v1.next(), __);
assert_eq!(v1.next(), __);
}
|
into_iter、iter 和 iter_mut
上一节提到,for 会对集合调用 into_iter 将其转为迭代器。但这并不是唯一方式。
into_iter、iter、iter_mut 都能把集合变成迭代器,但方式不同:
into_iter 会消耗集合,循环结束后集合不能再使用,因为所有权已在循环中转移。iter 在每次迭代中借用集合中的元素,循环后集合仍可重用。iter_mut 在每次迭代中可变借用集合中的元素,允许在原地修改集合。
- 🌟
1
2
3
4
5
6
7
8
9
| /* 让代码工作 */
fn main() {
let arr = vec![0; 10];
for i in arr {
println!("{}", i);
}
println!("{:?}",arr);
}
|
- 🌟
1
2
3
4
5
6
7
8
9
10
11
12
13
| /* 填空 */
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in names.__{
*name = match name {
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello",
}
}
println!("names: {:?}", names);
}
|
- 🌟🌟
1
2
3
4
5
6
7
8
9
10
11
| /* 填空 */
fn main() {
let mut values = vec![1, 2, 3];
let mut values_iter = values.__;
if let Some(v) = values_iter.__{
__
}
assert_eq!(values, vec![0, 2, 3]);
}
|
创建自定义迭代器
我们不仅可以从集合类型创建迭代器,还可以为自己的类型实现 Iterator 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
31
32
33
| struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter { count: 0 }
}
}
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
}
}
}
fn main() {
let mut counter = Counter::new();
assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
assert_eq!(counter.next(), Some(3));
assert_eq!(counter.next(), Some(4));
assert_eq!(counter.next(), Some(5));
assert_eq!(counter.next(), None);
}
|
- 🌟🌟🌟
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
| struct Fibonacci {
curr: u32,
next: u32,
}
// 为 `Fibonacci` 实现 `Iterator`。
// `Iterator` trait 只需定义 `next` 方法。
impl Iterator for Fibonacci {
// 可以用 Self::Item 引用该类型
type Item = u32;
/* 实现 next 方法 */
fn next(&mut self)
}
// 返回斐波那契序列生成器
fn fibonacci() -> Fibonacci {
Fibonacci { curr: 0, next: 1 }
}
fn main() {
let mut fib = fibonacci();
assert_eq!(fib.next(), Some(1));
assert_eq!(fib.next(), Some(1));
assert_eq!(fib.next(), Some(2));
assert_eq!(fib.next(), Some(3));
assert_eq!(fib.next(), Some(5));
}
|
消耗迭代器的方法
Iterator trait 有许多由标准库提供默认实现的方法。
消耗型适配器
其中一些方法会调用 next 来用完迭代器,因此称为消耗型适配器。
- 🌟🌟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/* 填空并修复错误 */
fn main() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
// sum 会取得迭代器的所有权,并通过反复调用 next 遍历元素
let total = v1_iter.sum();
assert_eq!(total, __);
println!("{:?}, {:?}",v1, v1_iter);
}
|
collect
除了把集合变成迭代器,我们还可以用 collect 把结果收集成集合,collect 会消耗迭代器。
- 🌟🌟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| /* 让代码工作 */
use std::collections::HashMap;
fn main() {
let names = [("sunface",18), ("sunfei",18)];
let folks: HashMap<_, _> = names.into_iter().collect();
println!("{:?}",folks);
let v1: Vec<i32> = vec![1, 2, 3];
let v2 = v1.iter().collect();
assert_eq!(v2, vec![1, 2, 3]);
}
|
迭代器适配器
能把一个迭代器变成另一个迭代器的方法称为迭代器适配器。可以链式调用多个适配器,以可读的方式完成复杂操作。
但所有迭代器都是惰性的,必须调用某个消耗型适配器,才能从迭代器适配器的调用中得到结果。
- 🌟🌟
1
2
3
4
5
6
7
8
| /* 填空 */
fn main() {
let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().__.__;
assert_eq!(v2, vec![2, 3, 4]);
}
|
- 🌟🌟
1
2
3
4
5
6
7
8
9
| /* 填空 */
use std::collections::HashMap;
fn main() {
let names = ["sunface", "sunfei"];
let ages = [18, 18];
let folks: HashMap<_, _> = names.into_iter().__.collect();
println!("{:?}",folks);
}
|
在迭代器适配器中使用闭包
- 🌟🌟
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
31
32
33
34
35
36
37
38
39
40
41
42
43
| /* 填空 */
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().__.collect()
}
fn main() {
let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let in_my_size = shoes_in_size(shoes, 10);
assert_eq!(
in_my_size,
vec![
Shoe {
size: 10,
style: String::from("sneaker")
},
Shoe {
size: 10,
style: String::from("boot")
},
]
);
}
|
你可以在这里找到答案(在 solutions 路径下)