matttproud.com (blog)

Rust Borrowed IntoIterator Trait

St. Paul, MN

For purposes of continued learning, I have been futzing around with Rust a little bit in my spare time. I had postponed doing this because I felt that the ecosystem was a bit too immature in terms of churn.1

I read the The Rust Programming Language several years ago. It’s a fine book, but I found it a little bit too superficial at the time. In the interim, the Android and Chrome Teams at Google published Comprehensive Rust. I’ve been slowly working through it, and it’s been the right level of technical depth for me.

One part I struggled a little bit with (I am a big dummy) was this lesson on implementing the IntoIterator trait:

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.

Here is what I came up with after about four tries:

 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 
struct Grid {  x_coords: Vec<u32>,  y_coords: Vec<u32>, }  impl<'a> IntoIterator for &'a Grid {  type Item = (u32, u32);  type IntoIter = GridIter<'a>;  fn into_iter(self) -> GridIter<'a> {  GridIter { grid: self, i: 0, j: 0 }  } }  struct GridIter<'a> {  grid: &'a Grid,  i: usize,  j: usize, }  impl<'a> Iterator for GridIter<'a> {  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}");  } } 

I need to admit that I find the explicit lifetime annotation hints a bit confusing. I have no problem modeling mutability and ownership in programs I write, but the way it needs to be communicated to the Rust compiler is a bit tedious.

To reach the above, I found using the IntoIterator implementation for the primitive slice to be useful to model this solution on (minimal viable complexity).


  1. My spare time is very limited these days. Back when I was more curious with the ecosystem, there was considerable churn. These days, I can’t afford to commit to too much learning/research that could end up being throwaway. ↩︎

Navigation:
Tags: