Rust For Loop
Introduction
The for
loop is one of the most commonly used control flow constructs in Rust. It provides a simple and efficient way to iterate over elements in a collection, range, or any other iterable object. Unlike languages like C or Java, Rust's for
loop is designed specifically for iteration, making it both safer and more concise.
In this tutorial, we'll explore how for
loops work in Rust, their syntax, common patterns, and practical applications. By the end, you'll be comfortable using for
loops in your Rust programs.
Basic Syntax
The basic syntax of a Rust for
loop is:
for element in collection {
// Code to execute for each element
}
Where:
element
is a variable that will hold each item from the collection, one at a timecollection
is any iterable object (array, vector, range, etc.)- The code block contains the instructions to execute for each element
Iterating Over Ranges
One of the most common uses of for
loops is to iterate over a range of numbers.
Simple Range Example
fn main() {
// Iterate over numbers 1 through 5 (inclusive)
for i in 1..=5 {
println!("Number: {}", i);
}
}
Output:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
In this example:
1..=5
creates an inclusive range from 1 to 5- The
for
loop iterates over each number in the range - For each iteration,
i
takes on the current value
Exclusive Range
If you don't want to include the upper bound, you can use ..
instead of ..=
:
fn main() {
// Iterate over numbers 0 through 4 (exclusive of 5)
for i in 0..5 {
println!("Index: {}", i);
}
}
Output:
Index: 0
Index: 1
Index: 2
Index: 3
Index: 4
Iterating Over Collections
Rust's for
loops really shine when working with collections like arrays, vectors, and slices.
Arrays
fn main() {
let colors = ["red", "green", "blue", "yellow"];
for color in colors {
println!("Color: {}", color);
}
}
Output:
Color: red
Color: green
Color: blue
Color: yellow
Vectors
fn main() {
let numbers = vec![10, 20, 30, 40, 50];
for number in &numbers {
println!("Number: {}", number);
}
// The vector is still usable here because we used a reference
println!("Vector length: {}", numbers.len());
}
Output:
Number: 10
Number: 20
Number: 30
Number: 40
Number: 50
Vector length: 5
Notice that we used &numbers
to iterate over references to the elements. This keeps ownership of the vector with the numbers
variable, so we can continue using it after the loop.
Getting Indices While Iterating
Sometimes you need both the index and the value. Rust provides the .enumerate()
method for this purpose:
fn main() {
let fruits = ["apple", "banana", "cherry", "date"];
for (index, fruit) in fruits.iter().enumerate() {
println!("Fruit at index {}: {}", index, fruit);
}
}
Output:
Fruit at index 0: apple
Fruit at index 1: banana
Fruit at index 2: cherry
Fruit at index 3: date
The enumerate()
method transforms each element into a tuple of (index, value)
.
Iterating Over Strings
Iterating over strings in Rust requires special consideration because of how Rust handles Unicode:
fn main() {
let message = "Hello, 世界!";
// Iterate over bytes
println!("Bytes:");
for byte in message.bytes() {
print!("{} ", byte);
}
println!();
// Iterate over characters (Unicode scalar values)
println!("Characters:");
for character in message.chars() {
print!("{} ", character);
}
println!();
}
Output:
Bytes:
72 101 108 108 111 44 32 228 184 150 231 149 140 33
Characters:
H e l l o , 世 界 !
Control Flow Within Loops
You can use continue
and break
statements to control the flow within a for
loop:
Continue
The continue
statement skips the rest of the current iteration and moves to the next one:
fn main() {
for i in 1..=10 {
if i % 2 == 0 {
// Skip even numbers
continue;
}
println!("Odd number: {}", i);
}
}
Output:
Odd number: 1
Odd number: 3
Odd number: 5
Odd number: 7
Odd number: 9
Break
The break
statement exits the loop entirely:
fn main() {
for i in 1..=100 {
if i > 5 {
println!("Stopping at 5");
break;
}
println!("Number: {}", i);
}
println!("Loop has ended");
}
Output:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Stopping at 5
Loop has ended
Returning Values from Loops
While not specific to for
loops (it's actually more common with loop
), it's worth noting that Rust allows you to return a value from a loop using break
:
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter * 2 > 20 {
break counter * 2;
}
};
println!("Result: {}", result);
}
Output:
Result: 22
This technique is less commonly used with for
loops but can be useful in some scenarios.
Patterns and Real-World Examples
Let's look at some practical examples of for
loops in Rust:
Example 1: Calculating Sum and Average
fn main() {
let grades = [85, 92, 78, 65, 88, 91];
let mut sum = 0;
for grade in grades {
sum += grade;
}
let average = sum as f32 / grades.len() as f32;
println!("Sum: {}", sum);
println!("Average: {:.2}", average);
}
Output:
Sum: 499
Average: 83.17
Example 2: Finding Items in a Collection
fn main() {
let inventory = vec!["sword", "shield", "potion", "map", "compass"];
let item_to_find = "map";
let mut found = false;
for item in &inventory {
if item == &item_to_find {
found = true;
break;
}
}
if found {
println!("You have a {} in your inventory!", item_to_find);
} else {
println!("You don't have a {} in your inventory.", item_to_find);
}
}
Output:
You have a map in your inventory!
Example 3: Processing 2D Data
fn main() {
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
println!("Matrix elements:");
for row in &matrix {
for &element in row {
print!("{} ", element);
}
println!();
}
println!("
Diagonal elements:");
for i in 0..matrix.len() {
print!("{} ", matrix[i][i]);
}
println!();
}
Output:
Matrix elements:
1 2 3
4 5 6
7 8 9
Diagonal elements:
1 5 9
Example 4: Filtering and Transformation
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut even_squares = Vec::new();
for num in &numbers {
if num % 2 == 0 {
even_squares.push(num * num);
}
}
println!("Original numbers: {:?}", numbers);
println!("Squares of even numbers: {:?}", even_squares);
}
Output:
Original numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Squares of even numbers: [4, 16, 36, 64, 100]
Visual Representation of For Loop Flow
Here's a diagram showing the control flow of a Rust for
loop:
Common Patterns and Best Practices
-
Use references (
&
) to iterate over collections when you don't need ownership:rustfor item in &collection { /* ... */ }
-
Use mutable references (
&mut
) when you need to modify collection items:rustfor item in &mut collection { /* ... */ }
-
Use
enumerate()
when you need both indices and values:rustfor (index, value) in collection.iter().enumerate() { /* ... */ }
-
Prefer
for
loops overwhile
loops for iteration - they're more concise and prevent common errors like off-by-one errors. -
Use inclusive ranges (
..=
) when you want to include the upper bound.
Common Mistakes
-
Trying to modify a collection while iterating over it directly - Rust's ownership system prevents this, which is actually a good thing! Use
&mut
references instead. -
Forgetting that ranges with
..
(without=
) exclude the upper bound. -
Using
.iter()
when iterating over a range - Ranges are already iterators, so there's no need for.iter()
.
Summary
The for
loop in Rust is a powerful and safe way to iterate over collections and ranges. Let's recap the key points:
- Rust's
for
loops work with any iterable, including ranges, arrays, vectors, and more - The basic syntax is
for element in collection { /* code */ }
- You can use ranges (
1..5
or1..=5
) to iterate over numbers - Use references (
&
or&mut
) to avoid transferring ownership during iteration - The
enumerate()
method gives you both indices and values - Control flow statements like
continue
andbreak
work withinfor
loops - Rust's ownership system ensures safe iteration, preventing common bugs found in other languages
With for
loops, you can write cleaner, safer, and more idiomatic Rust code. They're an essential tool in every Rust programmer's toolkit.
Exercises
To practice your understanding of for
loops in Rust, try these exercises:
-
Write a program that uses a
for
loop to find the sum of all even numbers from 1 to 100. -
Create a function that takes a vector of integers and returns a new vector containing only the prime numbers from the original vector.
-
Write a program that uses nested
for
loops to print a multiplication table from 1 to 10. -
Implement a function that takes a string and returns a new string with all vowels removed, using a
for
loop. -
Write a program that uses a
for
loop withenumerate()
to find and print the indices of all occurrences of a specific value in a vector.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)