IntoIterator
Iterator
トレイトは、イテレータを作成した後に反復処理を行う方法を示します。関連するトレイト IntoIterator
は、ある型に対するイテレータを作成する方法を定義します。これは for
ループによって自動的に使用されます。
struct Grid { x_coords: Vec<u32>, y_coords: Vec<u32>, } impl IntoIterator for Grid { type Item = (u32, u32); type IntoIter = GridIter; fn into_iter(self) -> GridIter { GridIter { grid: self, i: 0, j: 0 } } } struct GridIter { grid: Grid, i: usize, j: usize, } impl Iterator for GridIter { type Item = (u32, u32); fn next(&mut self) -> Option<(u32, u32)> { if self.i >= self.grid.x_coords.len() { self.i = 0; self.j += 1; if self.j >= self.grid.y_coords.len() { return None; } } let res = Some((self.grid.x_coords[self.i], self.grid.y_coords[self.j])); self.i += 1; res } } fn main() { let grid = Grid { x_coords: vec![3, 5, 7, 9], y_coords: vec![10, 20, 30, 40] }; for (x, y) in grid { println!("point = {x}, {y}"); } }
This slide should take about 5 minutes.
IntoIterator
のドキュメントをクリックしてご覧ください。IntoIterator
のすべての実装で、次の 2 つの型を宣言する必要があります。
Item
: 反復処理する型(i8
など)。IntoIter
:into_iter
メソッドによって返されるIterator
型。
IntoIter
とItem
は関連があり、イテレータはItem
と同じ型を持つ必要があります。すなわち、Option<Item>
を返します。
この例は、x 座標と y 座標のすべての組み合わせを反復処理しています。
main
でグリッドを 2 回反復処理してみましょう。これはなぜ失敗するのでしょうか。IntoIterator::into_iter
は self
の所有権を取得することに着目してください。
この問題を修正するには、&Grid
に IntoIterator
を実装し、Grid
への参照を GridIter
に保存します。
標準ライブラリ型でも同じ問題が発生する可能性があります。for e in some_vector
は、some_vector
の所有権を取得し、そのベクターの所有要素を反復処理します。some_vector
の要素への参照を反復処理するには、代わりに for e in &some_vector
を使用します。