IntoIterator
Iterator トレイトは、イテレータを作成したあとでどのように イテレートするか を示します。関連するトレイト IntoIterator は、ある型に対するイテレータの作成方法を定義します。これは for ループで自動的に使われます。
// 著作権 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 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}"); } }
IntoIteratorは、for ループを動作させるトレイトです。これはVec<T>のようなコレクション型や、それらへの参照である&Vec<T>や&[T]によって実装されています。範囲もこれを実装しています。これが、for i in some_vec { .. }でベクタをイテレートできる一方で、some_vec.next()は存在しない理由です。
IntoIterator のドキュメントを参照してください。IntoIterator のすべての実装は、2 つの型を宣言しなければなりません。
Item:i8のような、イテレート対象の型IntoIter:into_iterメソッドが返すIterator型
IntoIter と Item は結び付いていることに注意してください。イテレータは同じ Item 型を持たなければならず、これは Option<Item> を返すことを意味します
この例では、x 座標と y 座標のすべての組み合わせをイテレートしています。
main でグリッドを 2 回イテレートしてみてください。なぜこれは失敗するのでしょうか。IntoIterator::into_iter は self の所有権を受け取ることに注意してください。
この問題は、&Grid に対して IntoIterator を実装し、参照でイテレートする GridRefIter を作成することで修正できます。GridIter と GridRefIter の両方を含むバージョンは、この playground で利用できます。
同じ問題は標準ライブラリの型でも発生することがあります。for e in some_vector は some_vector の所有権を取得し、そのベクタの所有された要素をイテレートします。代わりに for e in &some_vector を使うと、some_vector の要素への参照をイテレートできます。