Iterator トレイト
Iterator トレイトは、オブジェクトを値のシーケンスを生成するためにどのように使用できるかを定義します。たとえば、スライスの要素を生成できるイテレータを作成したい場合、次のようになります。
// Copyright 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 struct SliceIter<'s> { slice: &'s [i32], i: usize, } impl<'s> Iterator for SliceIter<'s> { type Item = &'s i32; fn next(&mut self) -> Option<Self::Item> { if self.i == self.slice.len() { None } else { let next = &self.slice[self.i]; self.i += 1; Some(next) } } } fn main() { let slice = &[2, 4, 6, 8]; let iter = SliceIter { slice, i: 0 }; for elem in iter { dbg!(elem); } }
-
SliceIterの例は、前のスライドで示した C スタイルのforループと同じロジックを実装しています。 -
受講者に、イテレータは遅延評価されることを指摘してください。イテレータを作成しても構造体が初期化されるだけで、それ以外の処理は行われません。
nextメソッドが呼び出されるまで、何の処理も発生しません。 -
イテレータは有限である必要はありません。永遠に値を生成し続けるイテレータも完全に有効です。たとえば、
0..のような半開区間は、整数オーバーフローが発生するまで進み続けます。
さらに調べる
-
SliceIterの「実際の」版は、標準ライブラリ内のslice::Iter型です。ただし、実際の版では境界チェックをなくすために、内部ではインデックスの代わりにポインタを使用しています。 -
SliceIterの例は、参照を含む構造体の良い例であり、そのためライフタイム注釈を使用しています。 -
SliceIterにジェネリックパラメータを追加して、任意の種類のスライス(&[i32]だけでなく)で動作できるようにすることも示せます。