第13章: イテレータ (Iterators)

学習目標

  • Iterator トレイトの仕組みを理解する
  • イテレータアダプタ(map、filter、collect等)を使いこなす
  • ゼロコスト抽象化としてのイテレータを理解する
  • カスタムイテレータを実装できるようになる

---

13.1 イテレータとは何か

13.1.1 イテレータの基本概念

イテレータは、シーケンスの要素を順番に処理する抽象化です。Rustのイテレータは:

┌─────────────────────────────────────────────────────────┐
│              Rustイテレータの特徴                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. 遅延評価(Lazy Evaluation)                         │
│     └─ 必要になるまで計算しない                         │
│                                                         │
│  2. ゼロコスト抽象化                                     │
│     └─ 手書きループと同等の性能                         │
│                                                         │
│  3. コンポーザブル(composable)                         │
│     └─ チェーン可能、組み合わせやすい                   │
│                                                         │
│  4. 関数型プログラミングスタイル                         │
│     └─ 不変性、宣言的                                   │
│                                                         │
└─────────────────────────────────────────────────────────┘

13.1.2 基本的な使い方

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // 従来のforループ
    for i in &v {
        println!("{}", i);
    }

    // イテレータを使った方法
    v.iter().for_each(|x| println!("{}", x));

    // 実は、forループも内部でイテレータを使っている!
}

イテレータの生成方法

let v = vec![1, 2, 3];

// 1. iter() - 不変参照のイテレータ
let iter1 = v.iter();        // Item = &i32

// 2. iter_mut() - 可変参照のイテレータ
let iter2 = v.iter_mut();    // Item = &mut i32

// 3. into_iter() - 所有権を移すイテレータ
let iter3 = v.into_iter();   // Item = i32

---

13.2 Iterator トレイト

13.2.1 Iterator トレイトの定義

pub trait Iterator {
    type Item;

    // 必須メソッド
    fn next(&mut self) -> Option<Self::Item>;

    // デフォルト実装を持つメソッド(一部)
    fn count(self) -> usize { ... }
    fn map<B, F>(self, f: F) -> Map<Self, F> { ... }
    fn filter<P>(self, predicate: P) -> Filter<Self, P> { ... }
    // ... 70以上のメソッド!
}

重要な点

  • next() だけ実装すれば、他の70+メソッドが使える
  • Option を返す(None で終了を表現)
  • 13.2.2 手動でのイテレータ操作

    fn main() {
        let v = vec![1, 2, 3];
        let mut iter = v.iter();
    
        println!("{:?}", iter.next());  // Some(1)
        println!("{:?}", iter.next());  // Some(2)
        println!("{:?}", iter.next());  // Some(3)
        println!("{:?}", iter.next());  // None
        println!("{:?}", iter.next());  // None (何度呼んでもNone)
    }
    

    13.2.3 簡単なカスタムイテレータ

    // 1からnまでの数を生成するイテレータ
    struct Counter {
        current: u32,
        max: u32,
    }
    
    impl Counter {
        fn new(max: u32) -> Counter {
            Counter { current: 0, max }
        }
    }
    
    impl Iterator for Counter {
        type Item = u32;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.current += 1;
            if self.current <= self.max {
                Some(self.current)
            } else {
                None
            }
        }
    }
    
    fn main() {
        let counter = Counter::new(5);
    
        for num in counter {
            println!("{}", num);  // 1, 2, 3, 4, 5
        }
    }
    

    ---

    13.3 イテレータアダプタ

    13.3.1 アダプタとコンシューマ

    イテレータのメソッドは2種類に分類されます:

    ┌─────────────────────────────────────────────────────────┐
    │          アダプタ vs コンシューマ                        │
    ├─────────────────────────────────────────────────────────┤
    │                                                         │
    │  【アダプタ (Adapter)】                                  │
    │  - 新しいイテレータを返す                                │
    │  - 遅延評価(チェーンするだけでは実行されない)           │
    │  - 例: map, filter, take, skip                          │
    │                                                         │
    │  【コンシューマ (Consumer)】                             │
    │  - 最終的な値を返す                                      │
    │  - 実際に計算を実行する                                  │
    │  - 例: collect, sum, count, for_each                    │
    │                                                         │
    └─────────────────────────────────────────────────────────┘
    

    13.3.2 主要なアダプタ

    map - 変換

    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 - フィルタリング

    fn main() {
        let v = vec![1, 2, 3, 4, 5, 6];
    
        let evens: Vec<i32> = v.iter()
            .filter(|x| *x % 2 == 0)
            .copied()  // &i32 を i32 に変換
            .collect();
    
        println!("{:?}", evens);  // [2, 4, 6]
    }
    

    take / skip - 範囲制御

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        let first_three: Vec<_> = v.iter().take(3).collect();
        println!("{:?}", first_three);  // [1, 2, 3]
    
        let skip_two: Vec<_> = v.iter().skip(2).collect();
        println!("{:?}", skip_two);  // [3, 4, 5]
    }
    

    enumerate - インデックス付き

    fn main() {
        let v = vec!["a", "b", "c"];
    
        for (i, val) in v.iter().enumerate() {
            println!("{}: {}", i, val);
        }
        // 0: a
        // 1: b
        // 2: c
    }
    

    zip - 2つのイテレータを結合

    fn main() {
        let names = vec!["Alice", "Bob", "Charlie"];
        let ages = vec![25, 30, 35];
    
        let people: Vec<_> = names.iter()
            .zip(ages.iter())
            .collect();
    
        println!("{:?}", people);
        // [("Alice", 25), ("Bob", 30), ("Charlie", 35)]
    }
    

    13.3.3 チェーンの組み合わせ

    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)     // 偶数のみ
            .map(|x| x * x)               // 二乗
            .take(3)                      // 最初の3つ
            .collect();
    
        println!("{:?}", result);  // [4, 16, 36]
    }
    

    遅延評価の威力

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        // これだけでは何も実行されない!
        let iter = v.iter()
            .inspect(|x| println!("Processing: {}", x))
            .map(|x| x * 2)
            .filter(|x| *x > 5);
    
        println!("Iterator created");
    
        // collect() で初めて実行される
        let result: Vec<_> = iter.collect();
        println!("Result: {:?}", result);
    }
    
    // 出力:
    // Iterator created
    // Processing: 1
    // Processing: 2
    // Processing: 3
    // Processing: 4
    // Processing: 5
    // Result: [6, 8, 10]
    

    ---

    13.4 コンシューマメソッド

    13.4.1 collect - 収集

    use std::collections::HashMap;
    
    fn main() {
        let v = vec![1, 2, 3];
    
        // Vec<i32>
        let v1: Vec<i32> = v.iter().copied().collect();
    
        // String
        let chars = vec!['h', 'e', 'l', 'l', 'o'];
        let s: String = chars.iter().collect();
    
        // HashMap
        let pairs = vec![("a", 1), ("b", 2)];
        let map: HashMap<_, _> = pairs.into_iter().collect();
    }
    

    型推論の力

    fn main() {
        let v = vec![1, 2, 3];
    
        // 型注釈が必要(曖昧なため)
        let result: Vec<i32> = v.iter().copied().collect();
    
        // または、turbofish構文
        let result = v.iter().copied().collect::<Vec<i32>>();
    }
    

    13.4.2 fold - 畳み込み

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        // 合計
        let sum = v.iter().fold(0, |acc, x| acc + x);
        println!("Sum: {}", sum);  // 15
    
        // 積
        let product = v.iter().fold(1, |acc, x| acc * x);
        println!("Product: {}", product);  // 120
    
        // 文字列の結合
        let words = vec!["Hello", "Rust", "World"];
        let sentence = words.iter().fold(String::new(), |mut acc, word| {
            if !acc.is_empty() {
                acc.push(' ');
            }
            acc.push_str(word);
            acc
        });
        println!("{}", sentence);  // "Hello Rust World"
    }
    

    13.4.3 sum / product

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        let sum: i32 = v.iter().sum();
        println!("Sum: {}", sum);  // 15
    
        let product: i32 = v.iter().product();
        println!("Product: {}", product);  // 120
    }
    

    13.4.4 any / all

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        let has_even = v.iter().any(|x| x % 2 == 0);
        println!("Has even: {}", has_even);  // true
    
        let all_positive = v.iter().all(|x| *x > 0);
        println!("All positive: {}", all_positive);  // true
    
        let all_even = v.iter().all(|x| x % 2 == 0);
        println!("All even: {}", all_even);  // false
    }
    

    13.4.5 find / position

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        // 最初の偶数を見つける
        let first_even = v.iter().find(|x| *x % 2 == 0);
        println!("{:?}", first_even);  // Some(2)
    
        // 最初の偶数の位置
        let pos = v.iter().position(|x| *x % 2 == 0);
        println!("{:?}", pos);  // Some(1)
    }
    

    ---

    13.5 ゼロコスト抽象化の実例

    13.5.1 イテレータ vs ループの性能

    fn sum_loop(v: &[i32]) -> i32 {
        let mut sum = 0;
        for i in 0..v.len() {
            sum += v[i];
        }
        sum
    }
    
    fn sum_iterator(v: &[i32]) -> i32 {
        v.iter().sum()
    }
    
    fn main() {
        let v: Vec<i32> = (1..=1000000).collect();
    
        use std::time::Instant;
    
        let start = Instant::now();
        let s1 = sum_loop(&v);
        let elapsed1 = start.elapsed();
    
        let start = Instant::now();
        let s2 = sum_iterator(&v);
        let elapsed2 = start.elapsed();
    
        println!("Loop: {} in {:?}", s1, elapsed1);
        println!("Iterator: {} in {:?}", s2, elapsed2);
        // ほぼ同じ速度!
    }
    

    13.5.2 最適化されたコード

    コンパイラが生成する機械語はほぼ同一

    // 高水準なコード
    let sum: i32 = (1..=100).filter(|x| x % 2 == 0).sum();
    
    // コンパイル後は以下と同等
    let mut sum = 0;
    let mut i = 1;
    while i <= 100 {
        if i % 2 == 0 {
            sum += i;
        }
        i += 1;
    }
    

    ---

    13.6 高度なイテレータパターン

    13.6.1 flat_map - フラット化

    fn main() {
        let words = vec!["hello", "world"];
    
        // 各単語を文字のイテレータに変換してフラット化
        let chars: String = words.iter()
            .flat_map(|s| s.chars())
            .collect();
    
        println!("{}", chars);  // "helloworld"
    }
    

    13.6.2 scan - 状態を持つmap

    fn main() {
        let v = vec![1, 2, 3, 4, 5];
    
        // 累積和
        let cumsum: Vec<i32> = v.iter()
            .scan(0, |state, x| {
                *state += x;
                Some(*state)
            })
            .collect();
    
        println!("{:?}", cumsum);  // [1, 3, 6, 10, 15]
    }
    

    13.6.3 chain - イテレータの連結

    fn main() {
        let v1 = vec![1, 2, 3];
        let v2 = vec![4, 5, 6];
    
        let combined: Vec<i32> = v1.iter()
            .chain(v2.iter())
            .copied()
            .collect();
    
        println!("{:?}", combined);  // [1, 2, 3, 4, 5, 6]
    }
    

    13.6.4 partition - 分割

    fn main() {
        let v = vec![1, 2, 3, 4, 5, 6];
    
        let (evens, odds): (Vec<_>, Vec<_>) = v.iter()
            .partition(|x| *x % 2 == 0);
    
        println!("Evens: {:?}", evens);  // [2, 4, 6]
        println!("Odds: {:?}", odds);    // [1, 3, 5]
    }
    

    ---

    13.7 カスタムイテレータの実装

    13.7.1 Fibonacci イテレータ

    struct Fibonacci {
        curr: u64,
        next: u64,
    }
    
    impl Fibonacci {
        fn new() -> Self {
            Fibonacci { curr: 0, next: 1 }
        }
    }
    
    impl Iterator for Fibonacci {
        type Item = u64;
    
        fn next(&mut self) -> Option<Self::Item> {
            let current = self.curr;
    
            self.curr = self.next;
            self.next = current + self.next;
    
            Some(current)
        }
    }
    
    fn main() {
        let fib = Fibonacci::new();
    
        let first_10: Vec<u64> = fib.take(10).collect();
        println!("{:?}", first_10);
        // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
    }
    

    13.7.2 範囲イテレータ

    struct Range {
        start: i32,
        end: i32,
        step: i32,
    }
    
    impl Range {
        fn new(start: i32, end: i32, step: i32) -> Self {
            Range { start, end, step }
        }
    }
    
    impl Iterator for Range {
        type Item = i32;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.start < self.end {
                let current = self.start;
                self.start += self.step;
                Some(current)
            } else {
                None
            }
        }
    }
    
    fn main() {
        let range = Range::new(0, 10, 2);
    
        for num in range {
            println!("{}", num);  // 0, 2, 4, 6, 8
        }
    }
    

    13.7.3 逆順イテレータ

    struct ReverseVec<T> {
        data: Vec<T>,
        index: usize,
    }
    
    impl<T> ReverseVec<T> {
        fn new(data: Vec<T>) -> Self {
            let index = data.len();
            ReverseVec { data, index }
        }
    }
    
    impl<T: Clone> Iterator for ReverseVec<T> {
        type Item = T;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.index > 0 {
                self.index -= 1;
                Some(self.data[self.index].clone())
            } else {
                None
            }
        }
    }
    
    fn main() {
        let v = vec![1, 2, 3, 4, 5];
        let rev = ReverseVec::new(v);
    
        for num in rev {
            println!("{}", num);  // 5, 4, 3, 2, 1
        }
    }
    

    ---

    13.8 実践的なパターン

    13.8.1 データ処理パイプライン

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u32,
        salary: u32,
    }
    
    fn main() {
        let people = vec![
            Person { name: "Alice".to_string(), age: 25, salary: 50000 },
            Person { name: "Bob".to_string(), age: 30, salary: 60000 },
            Person { name: "Charlie".to_string(), age: 35, salary: 70000 },
            Person { name: "David".to_string(), age: 28, salary: 55000 },
        ];
    
        // 30歳以上で給与が60000以上の人の名前
        let qualified: Vec<String> = people.iter()
            .filter(|p| p.age >= 30 && p.salary >= 60000)
            .map(|p| p.name.clone())
            .collect();
    
        println!("{:?}", qualified);  // ["Bob", "Charlie"]
    }
    

    13.8.2 CSV処理

    fn main() {
        let csv = "Name,Age,City\n\
                   Alice,25,Tokyo\n\
                   Bob,30,Osaka\n\
                   Charlie,35,Kyoto";
    
        let data: Vec<Vec<&str>> = csv.lines()
            .skip(1)  // ヘッダーをスキップ
            .map(|line| line.split(',').collect())
            .collect();
    
        for row in data {
            println!("{:?}", row);
        }
    }
    

    13.8.3 グループ化

    use std::collections::HashMap;
    
    fn main() {
        let words = vec!["apple", "banana", "apricot", "blueberry", "avocado"];
    
        // 頭文字でグループ化
        let grouped: HashMap<char, Vec<&str>> = words.iter()
            .fold(HashMap::new(), |mut acc, word| {
                let first = word.chars().next().unwrap();
                acc.entry(first).or_insert_with(Vec::new).push(*word);
                acc
            });
    
        for (letter, group) in grouped {
            println!("{}: {:?}", letter, group);
        }
        // a: ["apple", "apricot", "avocado"]
        // b: ["banana", "blueberry"]
    }
    

    ---

    13.9 まとめ

    イテレータの利点

    ┌─────────────────────────────────────────────────────────┐
    │              イテレータを使うべき理由                    │
    ├─────────────────────────────────────────────────────────┤
    │                                                         │
    │  ✓ ゼロコスト抽象化                                      │
    │    └─ 手書きループと同等の性能                          │
    │                                                         │
    │  ✓ 宣言的で読みやすい                                    │
    │    └─ 「何をするか」に集中できる                        │
    │                                                         │
    │  ✓ コンポーザブル                                        │
    │    └─ 小さな部品を組み合わせて複雑な処理を構築          │
    │                                                         │
    │  ✓ 安全                                                  │
    │    └─ インデックス範囲外エラーの心配なし                │
    │                                                         │
    │  ✓ 遅延評価                                              │
    │    └─ 必要な分だけ計算                                  │
    │                                                         │
    └─────────────────────────────────────────────────────────┘
    

    次のステップ

    次の章では、クロージャについて学びます。イテレータと組み合わせることで、さらに強力な表現が可能になります。

    ---

    参考資料

  • The Rust Book: Iterators
  • Rust by Example: Iterators
  • Iterator trait documentation