gotcharustCritical
What is the difference between iter and into_iter?
Viewed 0 times
into_iterandbetweenthedifferenceiterwhat
Problem
I am doing the Rust by Example tutorial, which has this code snippet:
I am quite confused — for a
What is the use case/API for these two methods?
// 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?
Solution
TL;DR:
The first question is: "What is
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
For example,
Each variant is slightly different.
This one consumes the
The other two take the vector by reference (don't be fooled by the signature of
This one yields immutable references:
While this one yields mutable references:
So:
What is the difference between
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
which is very surprising for
Arrays now (post-1.53.0) implement
- The iterator returned by
into_itermay yield any ofT,&Tor&mut T, depending on the context.
- The iterator returned by
iterwill yield&T, by convention.
- The iterator returned by
iter_mutwill yield&mut T, by convention.
The first question is: "What is
into_iter?"into_iter comes from the IntoIterator trait:pub trait IntoIterator
where
::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 IntoIterator for Vec
impl IntoIterator for &'a Vec
impl IntoIterator for &'a mut VecEach variant is slightly different.
This one consumes the
Vec and its iterator yields values (T directly):impl IntoIterator for Vec {
type Item = T;
type IntoIter = IntoIter;
fn into_iter(mut self) -> IntoIter { /* ... */ }
}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 IntoIterator for &'a Vec {
type Item = &'a T;
type IntoIter = slice::Iter;
fn into_iter(self) -> slice::Iter { /* ... */ }
}While this one yields mutable references:
impl IntoIterator for &'a mut Vec {
type Item = &'a mut T;
type IntoIter = slice::IterMut;
fn into_iter(self) -> slice::IterMut { /* ... */ }
}So:
What is the difference between
iter and into_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:- Back then,
IntoIteratorwas not implemented for[T; N], only for&[T; N]and&mut [T; N].
- When a method is not implemented for a value, it is automatically searched for references to that value instead
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.Code Snippets
pub trait IntoIterator
where
<Self::IntoIter as Iterator>::Item == Self::Item,
{
type Item;
type IntoIter: Iterator;
fn into_iter(self) -> Self::IntoIter;
}impl<T> IntoIterator for Vec<T>
impl<'a, T> IntoIterator for &'a Vec<T>
impl<'a, T> IntoIterator for &'a mut Vec<T>impl<T> IntoIterator for Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(mut self) -> IntoIter<T> { /* ... */ }
}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> { /* ... */ }
}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> { /* ... */ }
}Context
Stack Overflow Q#34733811, score: 555
Revisions (0)
No revisions yet.