Skip to main content

Borrow or Take? The Simple Idea Behind Rust’s Iterators

The Problem

At first, I was lost, should I iter() or into_iter()?

I don't want to memorize, I want to understand. I just look at what I have (a reference, a value, or a mutable reference), then ask what kind of items I want to pull out.

Rust gives us three main entry points:

  • .iter() -> iterate over &T or yields reference
  • .iter_mut() -> iterate over &mut T or yields mutable reference
  • .into_iter() -> consume and yield T

Everything else is a variant of these.

Example 1: Consuming

fn main() { 
let v = vec![10, 20, 30];



// calls .into_iter() under the hood
for i in v {
println!("{i}")
}
// Prints:
// 10
// 20
// 30
// but then v is gone (moved)!

// so
dbg!(v);
// would fail (value used after move).

}

To prevent i from happen, borrow v:

Example 2: Borrowing

fn main() {

let v = vec!{1,2,3};

// equal to .iter()
for i in &v {
println!("{i}");
}

for i in v.iter() {
println!("{i}");
}

// then v is still available in the scope

dbg!(v);
// which will print: v = [ 1, 2, 3]
}

Takeaway

Keep container (v):

  • Read only -> .iter()
  • Modify in place -> .iter_mut() Drop container:
  • Take ownership -> .into_iter()