IntoIterator
The IntoIterator trait in std::iter defines how a type (or a reference to a type) converts into an Iterator, powering for loops across the language.
Trait Definition
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
Every type that implements Iterator automatically implements IntoIterator via a standard library blanket implementation (impl<I: Iterator> IntoIterator for I), returning itself from into_iter(self).
Desugaring of for Loops
A for loop in Rust is syntactic sugar for IntoIterator::into_iter:
// High-level syntax:
for item in collection {
// body
}
// Compiler desugaring:
{
let mut iter = IntoIterator::into_iter(collection);
while let Some(item) = iter.next() {
// body
}
}
Three IntoIterator Implementations on Standard Collections
Standard collections such as Vec<T> implement IntoIterator three times—once for the owned type Vec<T>, once for &Vec<T>, and once for &mut Vec<T>—so the for loop syntax controls ownership directly:
for Loop Target |
IntoIterator Implemented On |
Item Type |
Equivalent Method on Vec<T> |
|---|---|---|---|
for x in &vec |
&'a Vec<T> |
&'a T |
vec.iter() |
for x in &mut vec |
&'a mut Vec<T> |
&'a mut T |
vec.iter_mut() |
for x in vec |
Vec<T> |
T (consumes vec) |
vec.into_iter() |
fn main() {
let mut nums = vec![10, 20, 30];
// 1. Shared reference (&Vec<i32> -> Item = &i32)
for n in &nums {
print!("{n} ");
}
println!();
// 2. Mutable reference (&mut Vec<i32> -> Item = &mut i32)
for n in &mut nums {
*n += 5;
}
// 3. By value (Vec<i32> -> Item = i32, consumes nums)
for n in nums {
print!("{n} ");
}
println!();
}
10 20 30
15 25 35
Accepting Any Iterable in Functions
Bounding a function parameter with impl IntoIterator<Item = T> lets callers pass a Vec<T>, an array [T; N], a HashSet<T>, or a chained iterator adapter directly without calling .into_iter() or .collect() at the call site:
fn average(values: impl IntoIterator<Item = f64>) -> f64 {
let mut sum = 0.0;
let mut count = 0usize;
for v in values {
sum += v;
count += 1;
}
if count == 0 { 0.0 } else { sum / count as f64 }
}
fn main() {
println!("Array avg: {:.1}", average([2.0, 4.0, 6.0]));
println!("Range map: {:.1}", average((1..=5).map(f64::from)));
}
Array avg: 4.0
Range map: 3.0