Question
I am working through the Rust By Example tutorial and came across this code:
// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter().any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(|x| x == 2));
// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter().any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));
I am confused about the difference:
- For a
Vec,.iter()yields references and.into_iter()yields values. - For an array, these two seem to behave the same in this example.
What is the purpose of these two methods, and when should each one be used in Rust?
Short Answer
By the end of this page, you will understand how iter() and into_iter() differ in Rust, especially in terms of borrowing vs moving ownership. You will also see why Vec<T> and arrays can behave differently, how this changed across Rust editions, and how to choose the right iterator in real code.
Concept
In Rust, iter() and into_iter() are both ways to loop over a collection, but they represent different ownership behavior.
iter()borrows the collection and yields references to its items.into_iter()consumes the collection and yields owned items.
This distinction matters because Rust tracks ownership very strictly.
Core idea
For a collection like Vec<T>:
vec.iter()gives you&Tvec.into_iter()gives youT
That means:
- with
iter(), you can still use the original vector afterward because it was only borrowed - with
into_iter(), the vector is moved into the iterator, so you cannot use it afterward
There is also a third related method:
iter_mut()gives you&mut T
So the common pattern is:
Mental Model
Think of a collection as a box of items.
iter()is like opening the box and pointing at each item one by one. You are only looking, not taking.iter_mut()is like opening the box and adjusting each item in place.into_iter()is like handing over the whole box and letting someone take each item out. After that, you no longer own the box.
For a Vec<String>:
iter()gives you&String— you can read each stringinto_iter()gives youString— each string is moved out, so you now own it
This is why into_iter() is useful when you want to transform, return, or store values somewhere else without cloning them.
Syntax and Examples
Basic syntax
let v = vec![10, 20, 30];
for x in v.iter() {
println!("{}", x); // x is &i32
}
let v = vec![10, 20, 30];
for x in v.into_iter() {
println!("{}", x); // x is i32
}
Example: iter() borrows
let v = vec![1, 2, 3];
let has_two = v.iter().any(|&x| x == 2);
(, has_two);
(, v);
Step by Step Execution
Consider this code:
let v = vec![1, 2, 3];
let found = v.iter().any(|&x| x == 2);
println!("found = {}", found);
println!("v = {:?}", v);
Step by step
1. Create the vector
let v = vec![1, 2, 3];
v owns the vector and its contents.
2. Call iter()
v.iter()
This creates an iterator that borrows v and yields items of type &i32.
The iterator will produce:
Real World Use Cases
When iter() is used
iter() is common when you want to read data without taking ownership.
Examples
- checking whether a value exists in a list
- calculating a sum from borrowed data
- filtering items while keeping the original collection
- rendering data in a web server response
- inspecting configuration values
let users = vec!["alice", "bob", "carol"];
let has_bob = users.iter().any(|&name| name == "bob");
When into_iter() is used
into_iter() is useful when you want to consume a collection and move its values elsewhere.
Examples
- converting one collection into another
- moving
Stringvalues without cloning - building transformed output from owned input
- passing ownership into worker tasks or channels
let = [::(), ::()];
: <> = words.().(|s| s.()).();
Real Codebase Usage
In real Rust projects, developers choose between these iterator styles based on ownership needs.
Pattern: read-only processing with iter()
fn contains_admin(users: &[String]) -> bool {
users.iter().any(|name| name == "admin")
}
This is common because:
- it avoids taking ownership
- it works with slices and borrowed data
- it keeps APIs flexible
Pattern: transformation with into_iter()
fn uppercase_all(words: Vec<String>) -> Vec<String> {
words
.into_iter()
.map(|word| word.to_uppercase())
.collect()
}
This is common when the function receives ownership and returns a new owned collection.
Pattern: mutate in place with iter_mut()
Common Mistakes
1. Using into_iter() when you still need the collection
Broken code:
let v = vec![1, 2, 3];
let sum: i32 = v.into_iter().sum();
println!("{:?}", v); // error
Why it fails:
into_iter()consumesv
Fix:
let v = vec![1, 2, 3];
let sum: i32 = v.iter().sum();
println!("{:?}", v);
2. Forgetting that iter() yields references
Broken code:
Comparisons
Iterator methods compared
| Method | Yields | Ownership effect | Can use original collection after? | Common use |
|---|---|---|---|---|
iter() | &T | borrows | yes | read-only traversal |
iter_mut() | &mut T | mutable borrow | yes, after borrow ends | modify in place |
into_iter() | T | consumes | no | move values out |
iter() vs
Cheat Sheet
Quick rules
iter()→ borrow items as&Titer_mut()→ borrow items as&mut Tinto_iter()→ consume the collection and yieldT
Common patterns
v.iter()
v.iter_mut()
v.into_iter()
For Vec<T>
let v = vec![1, 2, 3];
v.iter(); // Iterator<Item = &i32>
v.into_iter(); // Iterator<Item = i32>
For arrays in modern Rust
let a = [1, 2, 3];
a.();
a.();
FAQ
Why does iter() return references in Rust?
Because iter() borrows the collection instead of consuming it. Returning references lets you access items without taking ownership.
Why does into_iter() consume the collection?
Its purpose is to turn the collection itself into an iterator. That usually means ownership moves into the iterator, so the original collection is no longer available.
Is into_iter() always better than iter()?
No. Use into_iter() only when you want to consume the collection. If you still need the collection afterward, use iter().
Why do old Rust examples show arrays behaving differently?
Because array into_iter() behavior changed over time, especially across Rust editions and older tutorial material. Modern Rust treats array into_iter() as yielding owned items.
What does a for loop use internally?
A for loop calls IntoIterator::into_iter() on the value you provide.
When should I use iter_mut()?
Mini Project
Description
Build a small Rust program that processes a list of task names to demonstrate the difference between borrowing and consuming iteration. You will inspect tasks with iter(), then transform owned task strings with into_iter(). This mirrors real applications where data is first checked, then moved into a new processed form.
Goal
Create a program that checks whether a task exists without consuming the original list, then consumes another list to build uppercase versions without cloning.
Requirements
- Create one
Vec<String>that is searched usingiter(). - Show that the original vector is still usable after the search.
- Create a second
Vec<String>that is transformed usinginto_iter(). - Convert the second vector's items to uppercase and collect them into a new vector.
- Print the final transformed vector.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Default Function Arguments in Rust: What to Use Instead
Learn how Rust handles default function arguments, why they are not supported, and practical patterns to achieve similar behavior.
Fixing Rust "linker 'cc' not found" on Debian in WSL
Learn why Rust shows "linker 'cc' not found" on Debian in WSL and how to fix it by installing the required C build tools.