Iterators

Owned vs. Borrowed Iteration

Choosing between borrowed iteration (.iter() / .iter_mut()) and owned iteration (.into_iter()) determines whether the original collection survives the loop and whether elements are accessed by reference or moved by value.

Side-by-Side Comparison

1. Shared Borrow:   vec.iter()      ──> yields &T      (vec remains usable)
2. Mutable Borrow:  vec.iter_mut()  ──> yields &mut T  (vec remains usable, modified)
3. Owned Move:      vec.into_iter() ──> yields T       (vec is consumed and freed)
Iteration Mode Method / for Syntax Item Type on Vec<T> Collection After Iteration Best Used When...
Shared borrow vec.iter() or for x in &vec &T Unchanged and accessible Inspecting, searching, or computing aggregates while keeping vec
Mutable borrow vec.iter_mut() or for x in &mut vec &mut T Modified in place and accessible Updating elements in place without reallocating
Owned (by value) vec.into_iter() or for x in vec T Consumed (moved) Transforming a collection into a new collection and avoiding .clone()

Avoiding Unnecessary .clone() Calls with .into_iter()

If a collection of heap-allocated items (Vec<String>) is no longer needed after transforming it, using .into_iter() moves each String into the new collection in $O(1)$ pointer-copy time instead of allocating new heap buffers with .iter().map(|s| s.clone()):

#[derive(Debug)]
struct User {
    username: String,
    active: bool,
}

fn extract_active_usernames(users: Vec<User>) -> Vec<String> {
    // `.into_iter()` moves `user.username` directly into the output `Vec<String>`
    // without cloning a single String:
    users
        .into_iter()
        .filter(|user| user.active)
        .map(|user| user.username)
        .collect()
}

fn main() {
    let roster = vec![
        User { username: String::from("alice"), active: true },
        User { username: String::from("bob"), active: false },
        User { username: String::from("carol"), active: true },
    ];

    let active_names = extract_active_usernames(roster);
    println!("Active: {active_names:?}");
}
Active: ["alice", "carol"]

Partial Consumption While Keeping the Container (Vec::drain)

When you need owned elements (T) like .into_iter(), but you want to keep the Vec<T> allocation alive for reuse (or only remove a subrange), use vec.drain(range):

fn main() {
    let mut queue = vec![
        String::from("job-1"),
        String::from("job-2"),
        String::from("job-3"),
    ];

    // Moves the first 2 Strings out by value while keeping `queue` valid:
    let batch: Vec<String> = queue.drain(0..2).collect();

    println!("Drained batch:   {batch:?}");
    println!("Remaining queue: {queue:?} (capacity: {})", queue.capacity());
}
Drained batch:   ["job-1", "job-2"]
Remaining queue: ["job-3"] (capacity: 3)