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:
elementis a variable that will hold each item from the collection, one at a timecollectionis 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..=5creates an inclusive range from 1 to 5- The
forloop iterates over each number in the range - For each iteration,
itakes 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
forloops overwhileloops 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
&mutreferences 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
forloops work with any iterable, including ranges, arrays, vectors, and more - The basic syntax is
for element in collection { /* code */ } - You can use ranges (
1..5or1..=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
continueandbreakwork withinforloops - 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
forloop 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
forloops 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
forloop. -
Write a program that uses a
forloop 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 feedback@compilenrun.com. I’d greatly appreciate your feedback! :)