迭代器(Iterator)#
迭代器(Iterator) 讓你逐一處理一系列元素,不需要手動管理索引。
Rust 的迭代器是 惰性(Lazy) 的:除非你呼叫消費型方法,否則不會執行任何計算。
1. Iterator Trait#
所有迭代器都實作 Iterator trait,核心只有一個方法:
1
2
3
4
| trait Iterator {
type Item; // 元素型別
fn next(&mut self) -> Option<Self::Item>; // 回傳下一個元素
}
|
每次呼叫 next() 回傳 Some(值) 直到元素耗盡,之後回傳 None。
2. 取得迭代器的三種方式#
對集合有三種方式取得迭代器,差別在於 所有權 的處理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| fn main() {
let v = vec![1, 2, 3];
// iter():不可變借用,v 之後仍可使用
for n in v.iter() {
println!("{n}"); // n 的型別是 &i32
}
println!("{:?}", v); // v 仍有效
// iter_mut():可變借用,可修改元素
let mut v = vec![1, 2, 3];
for n in v.iter_mut() {
*n *= 2;
}
println!("{:?}", v); // [2, 4, 6]
// into_iter():取得所有權,v 之後不可使用
let v = vec![1, 2, 3];
for n in v.into_iter() {
println!("{n}"); // n 的型別是 i32
}
// v 在此已失效
}
|
for 迴圈對集合預設呼叫 into_iter();對 &集合 使用則等同 iter()。
3. 消費型方法(Consuming Adaptors)#
呼叫後會耗盡迭代器、產生最終結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| fn main() {
let v = vec![1, 2, 3, 4, 5];
println!("總和:{}", v.iter().sum::<i32>()); // 15
println!("個數:{}", v.iter().count()); // 5
println!("最大:{:?}", v.iter().max()); // Some(5)
println!("最小:{:?}", v.iter().min()); // Some(1)
println!("任一 > 3:{}", v.iter().any(|&x| x > 3)); // true
println!("全部 > 0:{}", v.iter().all(|&x| x > 0)); // true
println!("找到 3:{:?}", v.iter().find(|&&x| x == 3)); // Some(3)
println!("位置:{:?}", v.iter().position(|&x| x == 3)); // Some(2)
}
|
collect — 收集成集合#
collect() 將迭代器轉換回集合,需標注目標型別:
1
2
3
4
5
| fn main() {
let v = vec![1, 2, 3];
let doubled: Vec<i32> = v.iter().map(|&x| x * 2).collect();
println!("{:?}", doubled); // [2, 4, 6]
}
|
4. 轉換型方法(Iterator Adaptors)#
產生新迭代器的方法, 本身是惰性的 ,需搭配消費型方法才會執行:
map — 轉換每個元素#
1
2
3
4
5
| fn main() {
let v = vec![1, 2, 3];
let doubled: Vec<i32> = v.iter().map(|&x| x * 2).collect();
println!("{:?}", doubled); // [2, 4, 6]
}
|
filter — 篩選元素#
1
2
3
4
5
| fn main() {
let v = vec![1, 2, 3, 4, 5, 6];
let evens: Vec<i32> = v.into_iter().filter(|x| x % 2 == 0).collect();
println!("{:?}", evens); // [2, 4, 6]
}
|
enumerate — 同時取得索引與值#
1
2
3
4
5
6
7
8
9
| fn main() {
let fruits = vec!["蘋果", "香蕉", "橘子"];
for (i, fruit) in fruits.iter().enumerate() {
println!("{i}: {fruit}");
}
// 0: 蘋果
// 1: 香蕉
// 2: 橘子
}
|
zip — 合併兩個迭代器#
1
2
3
4
5
6
7
8
| fn main() {
let names = vec!["Alice", "Bob", "Carol"];
let scores = vec![100, 85, 92];
for (name, score) in names.iter().zip(scores.iter()) {
println!("{name}: {score}");
}
}
|
chain — 串接兩個迭代器#
1
2
3
4
5
6
| fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let combined: Vec<i32> = a.into_iter().chain(b.into_iter()).collect();
println!("{:?}", combined); // [1, 2, 3, 4, 5, 6]
}
|
take 與 skip#
1
2
3
4
5
6
7
8
9
| fn main() {
let v = vec![1, 2, 3, 4, 5];
let first3: Vec<&i32> = v.iter().take(3).collect();
println!("{:?}", first3); // [1, 2, 3]
let skip2: Vec<&i32> = v.iter().skip(2).collect();
println!("{:?}", skip2); // [3, 4, 5]
}
|
flat_map — 攤平並轉換#
1
2
3
4
5
6
7
| fn main() {
let sentences = vec!["hello world", "foo bar"];
let words: Vec<&str> = sentences.iter()
.flat_map(|s| s.split_whitespace())
.collect();
println!("{:?}", words); // ["hello", "world", "foo", "bar"]
}
|
5. 迭代器鏈#
迭代器方法可以串接,形成流水線式的資料處理,且只遍歷資料一次:
1
2
3
4
5
6
7
8
9
10
11
| fn main() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: Vec<i32> = v.iter()
.filter(|&&x| x % 2 == 0) // 篩選偶數:2, 4, 6, 8, 10
.map(|&x| x * x) // 平方:4, 16, 36, 64, 100
.take(3) // 取前 3 個:4, 16, 36
.collect();
println!("{:?}", result); // [4, 16, 36]
}
|
等效的命令式寫法需要更多樣板程式碼,迭代器鏈更簡潔,且由於惰性求值,效能相當。
6. 自訂迭代器#
實作 Iterator trait 的 next() 方法即可建立自訂迭代器:
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
| struct Counter {
count: u32,
max: u32,
}
impl Counter {
fn new(max: u32) -> Counter {
Counter { count: 0, max }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < self.max {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
fn main() {
let v: Vec<u32> = Counter::new(5).collect();
println!("{:?}", v); // [1, 2, 3, 4, 5]
// 只要實作了 next(),所有迭代器方法都可以使用
let sum: u32 = Counter::new(5).sum();
println!("總和:{sum}"); // 15
// 兩個 Counter 搭配 zip
let pairs: Vec<(u32, u32)> = Counter::new(3)
.zip(Counter::new(3).skip(1))
.collect();
println!("{:?}", pairs); // [(1, 2), (2, 3)]
}
|
Reference#
https://doc.rust-lang.org/book/ch13-02-iterators.html