July 8, 2025•3 min
How do into_iter(), iter(), and iter_mut() differ?
m
mayoTable of Contents
These three methods are fundamental for working with collections in Rust, each serving distinct ownership and mutability use cases.
1. into_iter()
- Ownership-Consuming Iterator
- Takes ownership of the collection (
self
). - Produces owned values (
T
) when iterating. - Destroys the original collection (can't be used afterward).
let vec = vec!["a".to_string(), "b".to_string()];
for s in vec.into_iter() { // `vec` is moved here
println!("{}", s); // `s` is a String (owned)
}
// println!("{:?}", vec); // ERROR: `vec` was consumed
When to use:
- When you need to transform or consume the collection permanently.
- For chaining iterator adapters that need ownership (e.g.,
.filter().collect()
).
2. iter()
- Immutable Borrow Iterator
- Borrows the collection immutably (
&self
). - Produces references (
&T
). - Leaves the collection intact.
let vec = vec!["a", "b", "c"];
for s in vec.iter() { // Borrows `vec`
println!("{}", s); // `s` is &&str (reference)
}
println!("{:?}", vec); // OK: `vec` still valid
When to use:
- When you only need read-only access to elements.
- For operations like searching (
.find()
) or inspection.
3. iter_mut()
- Mutable Borrow Iterator
- Borrows the collection mutably (
&mut self
). - Produces mutable references (
&mut T
). - Allows in-place modification.
let mut vec = vec![1, 2, 3];
for num in vec.iter_mut() { // Mutable borrow
*num *= 2; // Modify in place
}
println!("{:?}", vec); // [2, 4, 6]
When to use:
- When you need to modify elements without reallocating.
- For bulk updates (e.g., applying transformations).
Key Differences Summary
Method | Ownership | Yields | Modifies Original? | Reuse Original? |
---|---|---|---|---|
into_iter() |
Consumes | T |
❌ (destroyed) | ❌ |
iter() |
Borrows | &T |
❌ | ✅ |
iter_mut() |
Mut borrow | &mut T |
✅ | ✅ |
Common Pitfalls
Accidental moves with
into_iter()
:let vec = vec![1, 2]; let _ = vec.into_iter(); // `vec` moved here // println!("{:?}", vec); // ERROR!
Simultaneous mutable access:
let mut vec = vec![1, 2]; let iter = vec.iter_mut(); // vec.push(3); // ERROR: Cannot borrow `vec` while iterator exists
Real-World Examples
iter()
for read-only processing:let words = vec!["hello", "world"]; let lengths: Vec<_> = words.iter().map(|s| s.len()).collect(); // [5, 5]
iter_mut()
for in-place updates:let mut scores = vec![85, 92, 78]; scores.iter_mut().for_each(|s| *s += 5); // [90, 97, 83]
into_iter()
for ownership transfer:let matrix = vec![vec![1, 2], vec![3, 4]]; let flattened: Vec<_> = matrix.into_iter().flatten().collect(); // [1, 2, 3, 4]
Performance Notes
iter()
anditer_mut()
are zero-cost (just pointers).into_iter()
may involve moves (but optimized for primitives likei32
).
Try This: What happens if you call iter_mut()
on a Vec<T>
where T
doesn’t implement Copy
, then try to modify the elements?
Answer: It works! The iterator yields &mut T
, allowing direct mutation (e.g., *item = new_value
).
Back to Blog
Share: