IntoIterator
O trait Iterator informa como iterar depois de criar um iterador. O trait relacionado IntoIterator define como criar um iterador para um tipo. Ele é usado automaticamente pelo laço 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}");
}
}
Clique na documentação para IntoIterator. Toda implementação de IntoIterator deve declarar dois tipos:
Item: o tipo sobre o qual iteramos, comoi8,IntoIter: o tipoIteratorretornado pelo métodointo_iter.
Observe que IntoIter e Item estão vinculados: o iterador deve ter o mesmo tipo Item, o que significa que ele retorna Option<Item>
O exemplo itera sobre todas as combinações de coordenadas x e y.
Tente iterar sobre o grid duas vezes em main. Por que isso falha? Observe que IntoIterator::into_iter assume a propriedade de self.
Corrija este problema implementando IntoIterator para &Grid e armazenando uma referência ao Grid em GridIter.
O mesmo problema pode ocorrer para tipos da biblioteca padrão: for e in some_vector assumirá a propriedade de some_vector e iterará sobre elementos owned desse vetor. Use for e in &some_vector em vez disso, para iterar sobre referências aos elementos de some_vector.