Rust's control flow may seem familiar, but it is subtly different from other languages in that it is expression-oriented. if can hold a value, loop can return a value, and for consumes an iterator. If you learn the differences in this episode, all future code will become more natural.
Learning Objectives
- Use
if/else/else ifin both sentence and expression forms. - The value is returned in the pattern
loopbreak value. - Select and use
whileandfor inaccording to the situation. - Exit the nested loop at once using the label loop.
Key concepts
If both branch types of the condition are the same, the entire if can be used as the value.
let label = if score >= 60 { "Pass" } else { "Retest" };
Only bool must be placed in the condition position (there is no integer truthy such as if 0).
let answer = loop {
if condition { break 42; }
};
If you send a value to break, it becomes the evaluation value of the loop expression. Very useful for infinite loop conditional exit patterns.
3) while vs for in
while: Repeat as long as the condition is true. When the index changes.for in: Iterator / range (0..n,0..=n) / traverse arrays, vectors, etc. First of all, if you don't need an index.
If you name the loop with 'label:, you can finish the loop from the inside to the outside with break 'label;.
See as example
//Part 4 Example 1: if·else·else Using if and if as expressions
fn main() {
let score = 78;
//Traditional if/else if/else chain
if score >= 90 {
println!("A");
} else if score >= 80 {
println!("B");
} else if score >= 70 {
println!("C");
} else {
println!("F");
}
//Rust's if is an expression, so it can be used as a value.
let label = if score >= 60 { "Pass" } else { "Retest" };
println!("Result: {label}");
//However, all branches must have the same type.
//let bad = if true { 1 } else { "Error" }; // ❌ Type mismatch
}
//Part 4 Example 2: The break value of loop and while
fn main() {
//loop is an infinite loop, but if you send a value to break, it becomes the expression value.
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; //This value is the result of the loop expression
}
};
println!("loop Result: {result}");
//while is a condition-based repetition
let mut n = 3;
while n > 0 {
println!("Countdown: {n}");
n -= 1;
}
println!("Fire!");
}
//Part 4 Example 3: for in range/array, and label loop
fn main() {
//0..5 is 0,1,2,3,4 (excluding the end). 0..=5 is 0~5 (including the end).
for i in 0..5 {
println!("i = {i}");
}
let arr = ["apple", "banana", "cherry"];
for fruit in arr.iter() {
println!("Fruit: {fruit}");
}
//If you need an index together, you can use enumerate()
for (idx, fruit) in arr.iter().enumerate() {
println!("{idx}: {fruit}");
}
//label loop — outer loop break.
'outer: for x in 0..3 {
for y in 0..3 {
if x + y == 3 {
println!("breaking at ({x},{y})");
break 'outer;
}
}
}
}
Common Mistakes
A. == is the correct comparison operator. = is an assignment, so it cannot be used in a conditional expression. Additionally, only bool can be placed in place of the if condition, so codes such as if 1 { ... } are not allowed.
A. To include the end, add =, like 0..=n. 0..n excludes the end.
A. If the intent of infinite loop is clear, loop is the standard. loop allows the compiler to perform smarter checks using information called “unfinished loops.” Being able to send values to break is also a privilege unique to loop.
A. Use the label ('outer: for ... { ... break 'outer; }). The intent is clearer than a pattern that checks for boolean flags.
Cleanup
ifis an expression — if both branch types are the same, it can be used as a value.loopis an infinite loop, and the value can be returned asbreak value.whileis condition-based, andfor inis iterator/range traversal.- Nested loop escapes are labeled
'name:break 'name;.
Try it yourself
Solve the assignment below. The reference solution is shown below.