Theme
Q035. How do collections and iterators transfer ownership?
Short Answer
Collection APIs choose whether iteration borrows or consumes. iter() yields &T, iter_mut() yields &mut T, and into_iter() takes the collection by value and yields owned T values. A for loop calls IntoIterator::into_iter on its expression, so for item in collection often consumes it, while &collection preserves ownership.
Deep Dive
The expression passed to iteration defines the ownership boundary:
for item in &collectionborrows and yields shared references;for item in &mut collectionmutably borrows and yields exclusive references;for item in collectionpasses the collection by value and usually yields owned elements.
An owning iterator holds responsibility for elements not yet yielded. If it is dropped before exhaustion, it drops the remaining elements and releases the collection's allocation.
Other APIs expose different controlled transfers. remove, swap_remove, and pop return owned elements while updating collection structure; drain borrows the collection mutably and yields removed owned elements; collect consumes an iterator and builds a new owner.
Internal Model
for syntax is lowered around IntoIterator::into_iter(expression) and repeated Iterator::next calls. Implementations for C, &C, and &mut C can therefore produce different iterator and item types.
For Vec<T>::into_iter, the iterator takes over the allocation and tracks which elements remain initialized, ensuring each yielded or unconsumed element is dropped exactly once.
Example
rust
fn main() {
let mut names = vec![String::from("Ada"), String::from("Grace")];
for name in &names {
println!("borrowed: {name}");
}
for name in &mut names {
name.push('!');
}
for name in names {
println!("owned: {name}");
}
}Common Mistakes
- Assuming every
forloop borrows its collection. - Calling
into_iterand then expecting the original non-Copycollection to remain usable. - Forgetting that a partially consumed owning iterator must drop remaining elements.
Follow-ups
- How does
drainyield owned values without consuming the collection itself? - What owns unconsumed elements inside
vec::IntoIter<T>? - How do iterator adapters transfer ownership of their closures and upstream iterators?
Related
- Q018. Why can't you move a value out of borrowed or indexed content?
- Q032. How does ownership work for struct fields?
- Q036. How do closures capture ownership, and what does
movemean for a closure?
References
- The Rust Programming Language
- Rust Reference
- Rust Standard Library