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.