TLDR

  • The iterator returned by into_iterator() can yield a T, &T, or &mut T, depending on the context, normally T unless there's some other circumstance.
  • The iterator returned by iter() will yield a &T by convention.
  • The iterator returned by iter_mut() will yield &mut T by convention.

WTF is into_iter()?

into_iter() comes from the IntoIterator trait, which you implement when you want to specify how a particular type gets converted into an iterator. Notably, if you want a type to be usable in a for loop, you must implement into_iter() for the type.

As an example, Vec<T> implements IntoIterator three times:

impl<T> IntoIterator for Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>
impl<'a, T> IntoIterator for &'a mut Vec<T>

Each of these is slightly different. The first one consumes the Vec and yields its T values directly.

The other two take the Vec by reference and yield immutable and mutable references of type T.

Yeah okay cool, so what's the difference though?

into_iter() is a generic method to obtain an iterator, and what this iterator yields (values, immutable references, or mutable references) is context dependent, and can sometimes be something you aren't expecting.

iter() and iter_mut() have return types independent of the context, and conventionally return immutable and mutable references respectively.

This is best shown with examples, so code blocks incoming:

#[test]
fn iter_demo() {
    let v1 = vec![1, 2, 3];
    let mut v1_iter = v1.iter();

    // iter() returns an iterator over references to the values
    assert_eq!(v1_iter.next(), Some(&1));
    assert_eq!(v1_iter.next(), Some(&2));
    assert_eq!(v1_iter.next(), Some(&3));
    assert_eq!(v1_iter.next(), None);
}

#[test]
fn into_iter_demo() {
    let v1 = vec![1, 2, 3];
    let mut v1_iter = v1.into_iter();

    // into_iter() returns an iterator over owned values in this particular case
    assert_eq!(v1_iter.next(), Some(1));
    assert_eq!(v1_iter.next(), Some(2));
    assert_eq!(v1_iter.next(), Some(3));
    assert_eq!(v1_iter.next(), None);
}

#[test]
fn iter_mut_demo() {
    let mut v1 = vec![1, 2, 3];
    let mut v1_iter = v1.iter_mut();

    // iter_mut() returns an iterator over mutable references to the values
    assert_eq!(v1_iter.next(), Some(&mut 1));
    assert_eq!(v1_iter.next(), Some(&mut 2));
    assert_eq!(v1_iter.next(), Some(&mut 3));
    assert_eq!(v1_iter.next(), None);
}