迭代器(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