Rust: iter() vs into_iter()
TLDR
- The iterator returned by
into_iterator()
can yield aT
,&T
, or&mut T
, depending on the context, normallyT
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);
}