イテレータが必要な理由

配列の内容を反復処理したい場合は、次を定義する必要があります。

  • 反復処理のどこまで進んでいるかを追跡するための状態。たとえば インデックス。
  • 反復処理がいつ終了するかを判定する条件。
  • ループごとに反復状態を更新するロジック。
  • その反復状態を使って各要素を取得するロジック。

C スタイルの for ループでは、これらを直接宣言します。

for (int i = 0; i < array_len; i += 1) {
    int elem = array[i];
}

Rust では、この状態とロジックをまとめて「イテレータ」と呼ばれる オブジェクトにします。

  • このスライドでは、Rust のイテレータが内部で何をしているかを説明するための文脈を示します。ここでは、 (おそらく)なじみのある C スタイルの for ループという構文を使って、 反復処理には何らかの状態と何らかのロジックが必要であることを示し、そのうえで次のスライドで イテレータがこれらをどのようにまとめるかを示します。

  • Rust には C スタイルの for ループはありませんが、同じことを while で表現できます:

    // Copyright 2024 Google LLC
    // SPDX-License-Identifier: Apache-2.0
    
    let array = [2, 4, 6, 8];
    let mut i = 0;
    while i < array.len() {
        let elem = array[i];
        i += 1;
    }

さらに詳しく

C と C++ では、for を使って配列の反復処理を表す別の方法もあります。配列の 先頭へのポインタと末尾へのポインタを使い、それらのポインタを 比較して、ループをいつ終了すべきかを判定できます。

for (int *ptr = array; ptr < array + len; ptr += 1) {
    int elem = *ptr;
}

受講者から質問があれば、これが Rust のスライスおよび配列の イテレータが内部で動作する仕組みであると説明できます(ただし、Rust のイテレータとして実装されています)。