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!("точка = {x}, {y}"); } }
Перейдіть до документації по IntoIterator
. Кожна реалізація IntoIterator
повинна декларувати два типи:
Item
: тип для ітерації, наприклад,i8
,IntoIter
: типIterator
, що повертається методомinto_iter
.
Зауважте, що IntoIter
і Item
пов’язані: ітератор повинен мати той самий тип Item
, що означає, що він повертає Option<Item>
У прикладі перебираються всі комбінації координат x та y.
Спробуйте виконати ітерацію над сіткою двічі в main
. Чому це не спрацьовує? Зверніть увагу, що IntoIterator::into_iter
отримує право власності на self
.
Виправте цю проблему, реалізувавши IntoIterator
для &Grid
і зберігаючи посилання на Grid
у GridIter
.
Така сама проблема може виникнути для стандартних бібліотечних типів: for e in some_vector
отримає право власності на some_vector
і буде перебирати елементи з цього вектора, які йому належать. Натомість використовуйте for e in &some_vector
для перебору посилань на елементи some_vector
.