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.

  1. struct Grid {
  2. x_coords: Vec<u32>,
  3. y_coords: Vec<u32>,
  4. }
  5. impl IntoIterator for Grid {
  6. type Item = (u32, u32);
  7. type IntoIter = GridIter;
  8. fn into_iter(self) -> GridIter {
  9. GridIter { grid: self, i: 0, j: 0 }
  10. }
  11. }
  12. struct GridIter {
  13. grid: Grid,
  14. i: usize,
  15. j: usize,
  16. }
  17. impl Iterator for GridIter {
  18. type Item = (u32, u32);
  19. fn next(&mut self) -> Option<(u32, u32)> {
  20. if self.i >= self.grid.x_coords.len() {
  21. self.i = 0;
  22. self.j += 1;
  23. if self.j >= self.grid.y_coords.len() {
  24. return None;
  25. }
  26. }
  27. let res = Some((self.grid.x_coords[self.i], self.grid.y_coords[self.j]));
  28. self.i += 1;
  29. res
  30. }
  31. }
  32. fn main() {
  33. let grid = Grid { x_coords: vec![3, 5, 7, 9], y_coords: vec![10, 20, 30, 40] };
  34. for (x, y) in grid {
  35. println!("point = {x}, {y}");
  36. }
  37. }

This slide should take about 5 minutes.

Click through to the docs for IntoIterator. Every implementation of IntoIterator must declare two types:

  • Item: the type to iterate over, such as i8,
  • “IntoIter”:“into_iter”方法返回的“Iterator”类型。

Note that IntoIter and Item are linked: the iterator must have the same Item type, which means that it returns Option<Item>

此示例对 x 坐标和 y 坐标的所有组合进行了迭代。

请尝试在 main 中对网格进行两次迭代。为什么会失败?请注意,IntoIterator::into_iter 获得了 self 的所有权。

如要解决此问题,请为 &Grid 实现 IntoIterator,并在 GridIter 中存储对 Grid 的引用。

对于标准库类型,可能会出现同样的问题:for e in some_vector 将获得 some_vector 的所有权,并迭代该矢量中的自有元素。请改用 for e in &some_vector 来迭代 some_vector 的元素的引用。