Question
I need to iterate over a Vec and access both the current element and its position in the vector. I assume Rust already provides this in the standard API, but I have not found it.
I want something like this:
fn main() {
let v = vec![1; 10];
for (pos, e) in v.iter() {
// do something here
}
}
How can I iterate through a Vec<T> while also getting the index of each element?
Short Answer
By the end of this page, you will understand how to iterate over a Vec<T> in Rust while also getting each element's index. You will learn to use .enumerate(), see how it works with .iter(), .iter_mut(), and .into_iter(), and understand common mistakes beginners make when working with indexed iteration.
Concept
In Rust, iterating over a collection and also tracking the position of each item is a very common task. The standard way to do this is with the .enumerate() adapter.
enumerate() takes any iterator and transforms it into a new iterator that yields pairs:
- the current index
- the current item
For a Vec<T>, you usually start with one of these iterator methods:
.iter()gives immutable references like&T.iter_mut()gives mutable references like&mut T.into_iter()gives owned values likeT
Then you add .enumerate() to include the index.
Example:
let v = vec![10, 20, 30];
for (index, value) in v.iter().enumerate() {
println!(, index, value);
}
Mental Model
Think of .iter() as a person handing you each item from a row of boxes.
Normally, you only get the item:
- box content:
10 - box content:
20 - box content:
30
When you add .enumerate(), that person also tells you which box number it came from:
- box
0:10 - box
1:20 - box
2:30
So enumerate() is like attaching a label number to every item as it comes through the iterator.
It does not change the vector itself. It just changes what the iterator produces.
Syntax and Examples
The most common syntax is:
for (index, item) in vec.iter().enumerate() {
// use index and item
}
Basic example
fn main() {
let v = vec![1, 2, 3];
for (pos, e) in v.iter().enumerate() {
println!("position: {}, value: {}", pos, e);
}
}
Output:
position: 0, value: 1
position: 1, value: 2
position: 2, value: 3
Here:
v.iter()produces&i32.enumerate()turns that into(usize, &i32)posis the indexeis a reference to the element
Step by Step Execution
Consider this example:
fn main() {
let v = vec![5, 6, 7];
for (pos, e) in v.iter().enumerate() {
println!("pos = {}, e = {}", pos, e);
}
}
Let’s trace it.
Step 1: Create the vector
let v = vec![5, 6, 7];
v is a Vec<i32> containing three elements.
Step 2: Call iter()
v.iter()
This creates an iterator over references:
&5&6
Real World Use Cases
Indexed iteration appears in many practical Rust programs.
Display numbered results
let tasks = vec!["build", "test", "deploy"];
for (i, task) in tasks.iter().enumerate() {
println!("{}. {}", i + 1, task);
}
Useful for:
- CLI menus
- todo lists
- ranked output
Validate imported rows
let rows = vec!["Alice", "", "Charlie"];
for (i, row) in rows.iter().enumerate() {
if row.is_empty() {
println!("Row {} is empty", i);
}
}
Useful for:
- CSV import tools
- parsers
- batch processing scripts
Update elements based on position
Real Codebase Usage
In real Rust codebases, developers often combine enumerate() with other iterator tools instead of writing manual counters.
Common pattern: immutable read with index
for (i, item) in items.iter().enumerate() {
println!("{}: {:?}", i, item);
}
Used for reporting, debugging, and rendering.
Common pattern: mutate each element with its index
for (i, item) in items.iter_mut().enumerate() {
*item += i as i32;
}
Used in data transformation and preprocessing.
Common pattern: skip or filter while keeping original positions
for (i, item) in items.iter().enumerate() {
if item.is_empty() {
continue;
}
println!("{} => {}", i, item);
}
This is useful when indexes matter for error messages or traceability.
Common Mistakes
1. Forgetting to call enumerate()
Broken code:
fn main() {
let v = vec![1, 2, 3];
for (pos, e) in v.iter() {
println!("{} {}", pos, e);
}
}
Why it fails:
v.iter()yields only one thing each time:&i32- the loop expects a pair like
(pos, e)
Fix:
for (pos, e) in v.iter().enumerate() {
println!("{} {}", pos, e);
}
2. Confusing references with values
With .iter(), the item is a reference.
let = [, , ];
(i, value) v.().() {
(, i, value);
}
Comparisons
| Approach | What it gives you | Consumes vector? | Common use |
|---|---|---|---|
v.iter() | &T | No | Read items without index |
v.iter().enumerate() | (usize, &T) | No | Read items with index |
v.iter_mut().enumerate() | (usize, &mut T) | No | Modify items with index |
v.into_iter().enumerate() | (usize, T) | Yes | Take ownership with index |
Cheat Sheet
Indexed iteration in Rust
Read-only iteration
for (i, item) in v.iter().enumerate() {
println!("{} -> {}", i, item);
}
iisusizeitemis&T
Mutable iteration
for (i, item) in v.iter_mut().enumerate() {
*item = i as i32;
}
itemis&mut T- use
*itemto modify the value
Owning iteration
for (i, item) in v.into_iter().enumerate() {
(, i, item);
}
FAQ
How do I get the index while iterating over a vector in Rust?
Use .enumerate() after creating an iterator:
for (i, item) in v.iter().enumerate() {
// ...
}
Does enumerate() work only with Vec?
No. It works with any iterator, including iterators from slices, arrays, strings, and custom iterator types.
Why is the index type usize?
Because indexes in Rust collections use usize, which is the platform-sized unsigned integer type used for memory indexing.
What is the difference between iter() and into_iter() with enumerate()?
iter()gives references like&Tinto_iter()gives owned values likeTand consumes the collection
Can I start counting from 1 instead of 0?
Mini Project
Description
Build a small Rust program that prints a numbered shopping list and marks empty entries as invalid. This demonstrates how to use .enumerate() in a realistic task where both the item and its position matter.
Goal
Create a program that loops through a vector, prints each item with a human-friendly number, and reports invalid entries using their index.
Requirements
- Create a
Vecof shopping list items, including at least one empty string. - Iterate through the vector using indexed iteration.
- Print valid items as a numbered list starting from 1.
- Detect empty items and print an error message with their zero-based index.
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.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Can a Struct Extend Another Struct in Rust? Composition vs Inheritance
Learn how Rust handles struct reuse without inheritance, using composition, traits, and wrapper structs with practical examples.