I am doing the Rust by Example tutorial, which has this code snippet:
// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));
// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter() .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));
I am quite confused — for a Vec
, the iterator returned from .iter
yields references and the iterator returned from .into_iter
yields values, but for an array these iterators are identical?
What is the use case/API for these two methods?
TL;DR:
into_iter
may yield any of T
, &T
or &mut T
, depending on the context.iter
will yield &T
, by convention.iter_mut
will yield &mut T
, by convention.The first question is: "What is into_iter
?"
into_iter
comes from the IntoIterator
trait:
pub trait IntoIterator where <Self::IntoIter as Iterator>::Item == Self::Item, { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }
You implement this trait when you want to specify how a particular type is to be converted into an iterator. Most notably, if a type implements IntoIterator
it can be used in a for
loop.
For example, Vec
implements IntoIterator
... thrice!
impl<T> IntoIterator for Vec<T> impl<'a, T> IntoIterator for &'a Vec<T> impl<'a, T> IntoIterator for &'a mut Vec<T>
Each variant is slightly different.
This one consumes the Vec
and its iterator yields values (T
directly):
impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(mut self) -> IntoIter<T> { /* ... */ } }
The other two take the vector by reference (don't be fooled by the signature of into_iter(self)
because self
is a reference in both cases) and their iterators will produce references to the elements inside Vec
.
This one yields immutable references:
impl<'a, T> IntoIterator for &'a Vec<T> { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; fn into_iter(self) -> slice::Iter<'a, T> { /* ... */ } }
While this one yields mutable references:
impl<'a, T> IntoIterator for &'a mut Vec<T> { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ } }
So:
What is the difference between
iter
andinto_iter
?
into_iter
is a generic method to obtain an iterator, whether this iterator yields values, immutable references or mutable references is context dependent and can sometimes be surprising.
iter
and iter_mut
are inherent methods. Their return type is therefore independent of the context, and will conventionally be iterators yielding immutable references and mutable references, respectively.
The author of the Rust by Example post used Rust pre-1.53.0 to illustrate the surprise coming from the dependence on the context (i.e., the type) on which into_iter
is called, and is also compounding the problem by using the fact that:
IntoIterator
was not implemented for [T; N]
, only for &[T; N]
and &mut [T; N]
.which is very surprising for into_iter
since all types (except [T; N]
) implement it for all 3 variations (value and references).
Arrays now (post-1.53.0) implement IntoIterator
in a regular fashion, so there's no surprise any longer.