IntoIterator
The Iterator
trait tells you how to iterate once you have created an iterator. The related trait IntoIterator
defines how to create an iterator for a type. It is used automatically by the for
loop.
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!("punto = {x}, {y}"); } }
Click through to the docs for IntoIterator
. Every implementation of IntoIterator
must declare two types:
Item
: el tipo sobre el que iteramos, comoi8
,IntoIter
: el tipoIterator
devuelto por el métodointo_iter
.
Ten en cuenta que IntoIter
y Item
están vinculados: el iterador debe tener el mismo tipo de Item
, lo que significa que devuelve Option<Item>
.
En el ejemplo se itera sobre todas las combinaciones de las coordenadas x e y.
Prueba a iterar sobre la cuadrícula dos veces en main
. ¿Por qué no funciona? Ten en cuenta que IntoIterator::into_iter
tiene la propiedad de self
.
Soluciona este problema implementando IntoIterator
para &Grid
y almacenando una referencia a Grid
en GridIter
.
Lo mismo puede ocurrir con los tipos de biblioteca estándar: for e in some_vector
adquirirá la propiedad de some_vector
e iterará sobre los elementos propios de ese vector. En su lugar, puedes utilizar for e in &some_vector
para iterar sobre referencias a elementos de some_vector
.