3.6.0. Before We Begin
Welcome to Chapter 3 of this Rust self-study series. It has 6 sections:
- Variables and Mutability
- Data Types: Scalar Types
- Data Types: Compound Types
- Functions and Comments
- Control Flow:
if else - Control Flow: Loops (this article)
Through the guessing game in Chapter 2 (beginners who have not read it are strongly encouraged to take a look), you should now have learned the basic Rust syntax. In Chapter 3, we will go one level deeper and learn the general programming concepts in Rust.
If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
3.6.1. Loops in Rust
Rust provides three kinds of loops:
loopwhilefor
3.6.2. The loop Loop
The loop keyword tells Rust to keep executing a block of code over and over until told to stop. Here is an example; it will keep printing 6657 up up!.
fn main(){
loop {
println!("6657 up up!");
}
}
You can use the break keyword inside a loop to tell the program when to stop.
fn main(){
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is: {}", result);
}
Code logic:
-
counteris initialized to0and increments by1on each loop. - When
counterequals10,breakexits the loop and returnscounter * 2(that is,20). -
loopis an expression, and its return value is the value passed tobreak, so it can be assigned directly toresult. -
resultis finally printed as20.
Code features:
- Rust's
loopis an expression, so its result can be bound directly to a variable. -
breakcan carry a return value (here,counter * 2) and use it as the result of theloop. - A
letstatement requires a semicolon after the assignment expression, so the closing brace}of theloopmust be followed by a semicolon.
3.6.3. while Conditional Loops
The while loop checks its condition before each execution of the loop body.
fn main() {
let mut countdown = 10; // Start the countdown at 10
println!("Rocket Launch Countdown:");
while countdown > 0 {
println!("T-minus {}...", countdown);
countdown -= 1; // Decrease by 1 each time
}
println!("🚀 Liftoff!");
println!("Houston, we have a problem.");
}
This is a simple while loop example, and its output is:
Rocket Launch Countdown:
T-minus 10...
T-minus 9...
T-minus 8...
T-minus 7...
T-minus 6...
T-minus 5...
T-minus 4...
T-minus 3...
T-minus 2...
T-minus 1...
🚀 Liftoff!
Houston, we have a problem.
3.6.4. Using for Loops to Traverse Collections
Of course, you can also use while and loop to iterate over a collection, but that is error-prone and inefficient.
Here is an example using while:
fn main() {
let numbers = [10, 20, 30, 40, 50];
let mut index = 0;
println!("Using while loop:");
while index < 5 {
println!("Number at index {}: {}", index, numbers[index]);
index += 1;
}
}
When using while, it is very easy to trigger a panic from an out-of-bounds index, and it also runs more slowly because the condition index < 5 must be checked every time.
Here is an example using for that achieves the same result:
fn main() {
let numbers = [10, 20, 30, 40, 50];
println!("Using for loop:");
for (index, number) in numbers.iter().enumerate() {
println!("Number at index {}: {}", index, number);
}
}
1. numbers.iter()
- Calls the
.iter()method on the collectionnumbersto create an immutable iterator that visits the elements one by one. In Rust, aforloop does not operate on the collection directly; it operates on an iterator that implements theIteratortrait..iter()is a commonly used method onVecand other collections that produces an iterator of references to the elements.forloops are concise and clear, and they can run code for every element in a collection. Because of their safety and simplicity, they are used the most in Rust.
2. .enumerate()
• Attaches an index to each element of the iterator. The index starts at 0 and is a usize value. .enumerate() wraps each element of the iterator into a (index, value) form, where index is the element's position in the collection and value is the current element pointed to by the iterator. .enumerate() returns a new iterator whose item type is (usize, &T), where T is the type of the elements in the collection. Here, numbers is an array of i32, so &T is &i32.
3. for (index, number) in ...
• The for loop supports destructuring tuples. (index, number) means that we directly destructure the (usize, &T) tuple produced by enumerate() into two variables: index, the current element's index; and number, the current element's reference (immutable).
Suppose numbers is [10, 20, 30, 40, 50]; the execution flow is as follows:
- Call
numbers.iter()to create an iterator. - Call
.enumerate()to produce an iterator of(index, element reference)pairs. - The
forloop destructures the index and the element:- First iteration:
index = 0, number = &10 - Second iteration:
index = 1, number = &20 - Third iteration:
index = 2, number = &30 - ...
- First iteration:
- Print
indexandnumberto output each element's index and value.
Because for loops are safe and concise, they are used the most in Rust.
3.6.5. Range
Range is provided by the standard library. You can use Range to generate numbers between two bounds (excluding the end). The rev method can be used to reverse a Range.
fn main() {
println!("Rocket Launch Countdown:");
for countdown in (1..=10).rev() {
println!("T-minus {}...", countdown);
}
println!("🚀 Liftoff!");
println!("Houston, we have a problem.");
}
This example uses for loops, Range, and rev to implement the rocket countdown shown in the while example above.
Code breakdown
-
(1..=10):- This is a
Rangerepresenting numbers from 1 to 10, inclusive. -
..=is the inclusive upper-bound range operator.
- This is a
-
.rev():- Reverses the iterator, producing a descending sequence from 10 down to 1.
Top comments (0)