[Rust] Control Flow: Mastering If Expressions and Loops
In programming, the ability to run code based on specific conditions or to repeat execution while a condition is met is fundamental. Rust provides several constructs to control the flow of your program, primarily if expressions and various types of loops.
1. if Expressions
An if expression allows you to branch your code depending on conditions. You provide a condition and tell the program: "If this condition is met, run this block; otherwise, don't."
Basic Usage
The most common form is combining if and else.
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
- Condition: The condition (e.g.,
number < 5) must evaluate to a boolean (bool). - Arms: The blocks of code associated with conditions (inside
{}) are often called 'arms'. - Strict Typing: Unlike languages like JavaScript or Ruby, Rust will not automatically try to convert non-Boolean types to a Boolean. Using a number directly in an
ifstatement (e.g.,if number { ... }) will result in a compilation error. You must be explicit, such asif number != 0.
Handling Multiple Conditions with else if
You can use else if to check multiple conditions in sequence.
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else {
println!("number is not divisible by 4 or 3");
}
}
Note: Rust executes only the first block where the condition is true. Once it finds one, it skips the rest. If you have too many conditions, consider using the
matchconstruct for better readability.
Using if in a let Statement
Since if is an expression, it returns a value. This allows you to use it on the right side of a let statement.
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
- Type Compatibility: Crucially, the values returned from every arm of the
ifmust be of the same type. You cannot return an integer in one arm and a string in another.
2. Repetition with Loops
Rust provides three kinds of loops: loop, while, and for.
The infinite loop
The loop keyword tells Rust to execute a block of code over and over again until you explicitly tell it to stop.
fn main() {
loop {
println!("again!");
break; // Use the break keyword to exit the loop.
}
}
Returning Values from Loops
You can pass the result of an operation out of a loop by adding the value you want to return after the break expression.
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}"); // Prints 20
}
Loop Labels
When dealing with nested loops, break and continue apply to the innermost loop. You can use loop labels (starting with a single quote ') to specify which loop you want to exit.
fn main() {
let mut count = 0;
'counting_up: loop {
let mut remaining = 10;
loop {
if remaining == 9 { break; } // Exits the inner loop
if count == 2 { break 'counting_up; } // Exits the outer loop
remaining -= 1;
}
count += 1;
}
}
Conditional Loops with while
The while loop runs as long as a condition remains true.
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
Looping Through a Collection with for
For safety and efficiency, for is the most recommended way to iterate over collections like arrays.
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
- Safety: Using
foreliminates the risk of "index out of bounds" errors that might occur withwhileloops and manual indexing. - Ranges: To run code a certain number of times, use a
Rangelike(1..4). You can also use.rev()to reverse the sequence.
Summary
- if: Used for branching. Must have a
boolcondition and can be used as an expression. - loop: Infinite repetition. Useful for retrying operations and returning values via
break. - while: Repeats code while a condition is true.
- for: The most common and safest way to iterate over collections or ranges.