Skip to content

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 &collection borrows and yields shared references;
  • for item in &mut collection mutably borrows and yields exclusive references;
  • for item in collection passes 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 for loop borrows its collection.
  • Calling into_iter and then expecting the original non-Copy collection to remain usable.
  • Forgetting that a partially consumed owning iterator must drop remaining elements.

Follow-ups

  • How does drain yield 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?

References

  • The Rust Programming Language
  • Rust Reference
  • Rust Standard Library