IntoIterator для ссылок
Если реализовать IntoIterator напрямую для типа, создание итератора забирает владение объектом, поэтому распространённый паттерн — реализовать его для ссылки, чтобы можно было создавать заимствующие итераторы.
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
struct Grid {
x_coords: Vec<u32>,
y_coords: Vec<u32>,
}
impl<'a> IntoIterator for &'a Grid {
type Item = (&'a u32, &'a u32);
type IntoIter = GridRefIter<'a>;
fn into_iter(self) -> GridRefIter<'a> {
GridRefIter { grid: self, i: 0, j: 0 }
}
}
struct GridRefIter<'a> {
grid: &'a Grid,
i: usize,
j: usize,
}
impl<'a> Iterator for GridRefIter<'a> {
type Item = (&'a u32, &'a u32);
fn next(&mut self) -> Option<Self::Item> {
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}");
}
// Сетка остаётся доступной после цикла.
dbg!(&grid.x_coords);
}
-
Реализовав
IntoIteratorдля&Grid, мы можем передать ссылку в циклforи получить заимствующий итератор. Это позволяет заимствовать объект сетки в цикле, не забирая владение им. -
Этот playground показывает, что
GridIterиGridRefIterможно использовать одновременно. -
Этот паттерн широко используется в стандартной библиотеке для её типов коллекций: он позволяет неявно создавать владеющие и заимствующие итераторы в зависимости от того, передаётся ли объект по значению, по ссылке или по изменяемой ссылке.
-
Откройте документацию
IntoIteratorи покажите реализации для[T; N],&[T; N]и&mut [T; N]. Покажите, что они создают разные итераторы с разными типами элементов:- Итератор для
[T; N]выдаётTпо значению. - Итератор для
&[T; N]выдаёт&T. - Итератор для
&mut [T; N]выдаёт&mut T.
- Итератор для