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: the Iterator type returned by the into_iter method.

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

The example iterates over all combinations of x and y coordinates.

Try iterating over the grid twice in main. Why does this fail? Note that IntoIterator::into_iter takes ownership of self.

Fix this issue by implementing IntoIterator for &Grid and storing a reference to the Grid in GridIter.

The same problem can occur for standard library types: for e in some_vector will take ownership of some_vector and iterate over owned elements from that vector. Use for e in &some_vector instead, to iterate over references to elements of some_vector.