// Function to create a formatted banner
fn banner(sep: &str, nchar: usize, message: &str) {
let sep = sep.repeat(nchar);
let message = format!("{:^width$}", message, width = nchar);
println!("\n{}\n{}\n{}", sep, message, sep);
}
Iterating with for .. in
The for
loop is another powerful and versatile control flow construct in Rust that allows for iterating over collections or ranges of values in a concise and readable manner. It is the most common and idiomatic way to perform iterations in Rust, providing a robust mechanism for traversing arrays, vectors, slices, and other iterable data structures.
Introduction to for
Loops
The for
loop simplifies the process of iterating over collections or ranges by automatically handling the iteration logic. This not only makes the code more readable and less error-prone but also leverages Rust's strong type system and ownership model to ensure safety and performance. The for
loop is preferred for most iteration tasks due to its clear syntax and ability to work seamlessly with Rust's iterators.
Syntax of for
Loop
The general syntax of a for
loop in Rust is as follows:
#![allow(unused)] fn main() { for item in collection { // Code to execute for each item in the collection } }
The Mechanism of for
Loop in Rust
- Initialization: The loop initializes an iterator for the specified collection or range.
- Iteration: For each iteration, the loop retrieves the next item from the iterator and executes the loop body with this item.
- Termination: The loop continues until the iterator is exhausted, meaning there are no more items to retrieve.
Advantages of for
Loops
- Readability: The syntax of for loops is clean and expressive, making it easy to understand the intent of the iteration.
- Safety: Rust's ownership and borrowing rules ensure that
for
loops do not cause data races or invalid memory access. - Efficiency: The Rust compiler optimizes
for
loops to minimize overhead, making them highly efficient for iterating over large collections. - Flexibility: for loops can be used with a wide variety of iterable structures, including arrays, vectors, slices, and custom iterators.
Example: Iterating Over a Range (Inclusive)
The for
loop in Rust can be effectively used to iterate over a range of values. When specifying a range, you can use the inclusive range syntax (..=
) to ensure that the upper bound is included in the iteration This is particularly useful when you need to include both the start and end values in your loop. Or you can use the non-inclusive range using this syntax (..
), remember that when using the non-exlusive syntax, the last item won't be included.
Example
Let us consider the following example where we iterate over an inclusive range of integers from 1 to 5:
fn main() {
banner("*", 62, "Iterating over a range of integer values using for loop");
// Use an inclusive range to iterate from 1 to 5
for number in 1..=5 {
println!("The number is: {}", number);
}
println!("Loop ended here");
println!("{}", "*".repeat(62));
}
main();
**************************************************************
Iterating over a range of integer values using for loop
**************************************************************
The number is: 1
The number is: 2
The number is: 3
The number is: 4
The number is: 5
Loop ended here
**************************************************************
Code in Details
Initialization:
- The
for
loop initializes an iterator over the inclusive range1..=5
. This range includes all integers from 1 to 5, both endpoints inclusive.
Iteration:
- The loop begins iterating over the range. In each iteration, the
number
variable takes on the value of the current item from the range.
Loop Body:
- The code inside the loop body (
println!("The number is: {}", number);
) executes for each value in the range. This statement prints the current value ofnumber
to the console.
Termination:
- The loop continues to iterate until all values in the range have been processed. In this example, it iterates five times, corresponding to the values 1, 2, 3, 4, and 5.
Detailed Walkthrough
-
First Iteration:
number = 1
- The loop body prints:
The number is: 1
-
Second Iteration:
number = 2
- The loop body prints:
The number is: 2
-
Third Iteration:
number = 3
- The loop body prints:
The number is: 3
-
Fourth Iteration:
number = 4
- The loop body prints:
The number is: 4
-
Fifth Iteration:
number = 5
- The loop body prints:
The number is: 5
After the fifth iteration, the range is exhausted, and the loop terminates.
If we were to iterate over a non-inclusive range, the end point would not be included in the iteration. Here is the same example as above, but with non-inclusive syntax:
fn main() {
banner("*", 62, "Iterating over a range of integer values using for loop");
// Use an inclusive range to iterate from 1 to 5
for number in 1..5 {
println!("The number is: {}", number);
}
println!("Loop ended here");
println!("{}", "*".repeat(62));
}
main();
**************************************************************
Iterating over a range of integer values using for loop
**************************************************************
The number is: 1
The number is: 2
The number is: 3
The number is: 4
Loop ended here
**************************************************************
As we can observe, the value 5
is not included in the output.
Example
fn main() {
let array = [10, 20, 30, 40, 50];
for element in array.iter() {
println!("The value is: {}", element);
}
}
main();
The value is: 10
The value is: 20
The value is: 30
The value is: 40
The value is: 50
Example: Iterating Over a Range of Characters
We can also iterate over a range of characters using the for
loop. This is particularly useful when you need to perform operations on a sequence of characters in a specific range. The syntax for character ranges is similar to that of numerical ranges.
Example
Consider the following example where we iterate over an inclusive range of characters from 'a'
to 'e'
:
fn main() {
banner("*", 52, "Iterating over a range of characters example");
for c in 'a'..='e' { // inclusive e
println!("Char: {}", c);
}
println!("{}", "*".repeat(52));
}
main();
****************************************************
Iterating over a range of characters example
****************************************************
Char: a
Char: b
Char: c
Char: d
Char: e
****************************************************
Example: Iterating Over an Array
The for
loop can be used to iterate over the elements of an array. This is a common use case for for
loops, as it allows for concise and readable traversal of array elements.
Example
Consider the following example where we iterate over an array of integers:
fn main() {
banner("*", 52, "Iterating over an array");
let numbers = [10, 20, 30, 40, 50];
for number in numbers {
println!("The number is: {}", number);
}
println!("{}", "+".repeat(52));
}
main();
****************************************************
Iterating over an array
****************************************************
The number is: 10
The number is: 20
The number is: 30
The number is: 40
The number is: 50
++++++++++++++++++++++++++++++++++++++++++++++++++++
Example: Iterating Over a Vector
Another collection the for
loop can also be used with to iterate over the elements of a vector. Vectors are similar to arrays but are dynamically sized, making them a common choice for collections where the number of elements may change.
Example
Consider the following example where we iterate over a vector of integers:
fn main() {
banner("*", 52, "Iterating over a vector");
let numbers = vec![10, 20, 30, 40, 50];
for number in &numbers {
println!("The number is: {}", number);
}
println!("{}", "+".repeat(52));
// println!("{:?}", numbers); if we didn't use `&numbers`, this would cause a compile error.
}
main();
****************************************************
Iterating over a vector
****************************************************
The number is: 10
The number is: 20
The number is: 30
The number is: 40
The number is: 50
++++++++++++++++++++++++++++++++++++++++++++++++++++
Notice that with vectors, the &numbers
syntax borrows the vector, allowing us to iterate over its elements without taking ownership. Ownership will be discussed in a different chapter in more detial.
Nested for Loops
In Rust, nested for loops allow you to iterate over multiple collections or ranges simultaneously. This is useful when you need to perform operations that involve combinations of elements from different collections or when working with multidimensional data structures.
Syntax of Nested for Loops
The general syntax for nested for loops is straightforward, with one for loop placed inside another. Each loop can iterate over its respective collection or range.
#![allow(unused)] fn main() { for item1 in collection1 { for item2 in collection2 { // code to execute for each combination of item1 and item2 } } }
Example: Nested for Loop with Ranges
Consider the following example where we use nested for loops to iterate over two ranges:
fn main() {
banner("*", 52, "Nested for loop");
for i in 1..=3 {
for j in 1..=3 {
println!("i: {}, j: {}", i, j);
}
}
println!("{}", "*".repeat(52));
}
main();
****************************************************
Nested for loop
****************************************************
i: 1, j: 1
i: 1, j: 2
i: 1, j: 3
i: 2, j: 1
i: 2, j: 2
i: 2, j: 3
i: 3, j: 1
i: 3, j: 2
i: 3, j: 3
****************************************************
- In this example:
- The outer loop initializes an iterator over the inclusive range 1..=3, iterating over the values 1, 2, and 3.
- For each iteration of the outer loop, the inner loop initializes its own iterator over the inclusive range 1..=3.
- The outer loop continues until all values in its range have been processed. For each value of the outer loop, the inner loop runs to completion before the outer loop proceeds to the next value.
Conclusion
In this section, we explored the various ways to use the for
loop in Rust to iterate over different types of collections. The for
loop is a powerful and flexible control flow construct that allows for concise and efficient iteration over arrays, vectors, ranges, characters, and other data structures.
-
We began with a detailed introduction to the
for
loop, highlighting its syntax and advantages. We then provided examples of usingfor
loops with inclusive and non-inclusive ranges, demonstrating how to iterate over sequences of numbers and characters. -
We also covered the use of
for
loops with arrays and vectors, which are commonly used collections in Rust. By iterating over these collections, we can perform operations on each element in a straightforward and readable manner.