Rust: Rust Loops and Iteration
Last updated: 2026-08-26
A loop in Rust isn't just a simple "infinite loop"—it "spits out" the value of the last calculation.
Each of the three types of loops has its own use case: loop infinite loops (with return values), while conditional loops, and for set iteration.
1. What You'll Learn
- Use
loopto create an infinite loop and return a value - Use
whilefor conditional looping - Use
forto iterate over sets and ranges - Use
breakandcontinueto control the loop process - Use a loop label to break out of a nested loop
- Using the range expressions
0..nand0..=n
2. The Story of a Maze Explorer
(1) Suffering: Getting Lost in a Maze
Alex is developing a maze game. The maze has a three-layered nested structure:
Outer layer (Dungeon) -> Middle layer (Room) -> Inner layer (Treasure Chest)
The player needs to go deeper and deeper to find the exit, but he finds it difficult to write the code:
- After finding the key in the treasure chest, I wanted to jump up to the room level—but
breakcan only jump up one level - You have to search every room to open the door—should you use
whileorfor? - The number of levels in the maze is fixed—but the number of rooms on each level varies.
"If we could label each loop, we could just jump to wherever we want..."
(2) Rust's Solution for Loops
fn main() {
let mut found_exit = false;
let maze = [
["empty", "empty", "key"],
["empty", "monster", "empty"],
["exit", "empty", "trap"],
];
// Outer Label 'outer Naming Dungeon Cycles
'outer: for (row, floor) in maze.iter().enumerate() {
println!("Enter the dungeon, Floor #{}", row + 1);
for (col, room) in floor.iter().enumerate() {
match *room {
"exit" => {
println!(" Find the Exit!Location: ({}, {})", row, col);
found_exit = true;
break 'outer; // Exit two nested loops immediately
}
"key" => println!(" Get the keys (Location: {},{})", row, col),
"monster" => println!(" There's a monster!Skip this room"),
_ => println!(" Vacant Room {}", col),
}
}
}
println!("Have you found the exit?: {}", found_exit);
}
Rust's loop labels (
'outer) allowbreakto break out of loops at any level. This is safer thangoto—it doesn't jump to an arbitrary location in the code, but only breaks out of the loop.
3. Comparison of the Three Loops
graph TB
A[Rust Loop] --> B[loop: Infinite Loop]
A --> C[while: Conditional Loops]
A --> D[for: Set Iteration]
B --> E[Until break up to and including]
B --> F[Available break Return Value]
C --> G[Check the condition before each loop]
D --> H[Iterating Through a Set Automatically/Scope]
D --> I[Most Commonly Used,Safest]
| Characteristics | loop |
while |
for |
|---|---|---|---|
| When to Use | Undefined termination condition | Condition-driven | Iterating over a set or range |
| Return Value | break value May return a value |
Cannot return a value | Cannot return a value |
| Infinite Loop | Native | while true |
Not suitable |
| Performance | Optimal (the compiler knows it will loop) | Slightly worse (checks the condition each time) | Optimal (directly driven by the iterator) |
| Use Cases | Retry/Polling | Conditional Wait | Iterate Through Arrays/Vectors/Ranges |
(2) Comparing break and continue
| Keyword | Function | Can Return a Value | Used With Tags |
|---|---|---|---|
break |
Exit the current loop | break value; (loop only) |
break 'label; |
continue |
Skip the remainder of this loop | Cannot | continue 'label; |
(3) Scope Expressions
| Notation | Meaning | Includes End Value | Example |
|---|---|---|---|
start..end |
Semi-open interval | No | 0..5 → 0, 1, 2, 3, 4 |
start..=end |
Closed interval | Yes | 0..=5 → 0, 1, 2, 3, 4, 5 |
..end |
From 0 to end | No | ..3 → 0, 1, 2 |
start.. |
From start to end | — | 3.. → 3, 4, 5, ... |
4. Loop Examples
▶ Example 1: Infinite loops with loop and return values with break (Difficulty ⭐)
Output:
Loop ran 5 times, break returned: <result>
Retry 0 Success on the next attempt: <success>
// ============================================
// loop Loop:A simulation of the "Guess the Number" game"Let's try again"
// ============================================
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 5 {
break counter * 2; // break Can have a return value!
}
};
println!("Loop ran 5 times, break returned: {}", result);
// Real-World Scenarios:Keep trying until you succeed
let mut attempts = 0;
let success = loop {
attempts += 1;
if attempts >= 3 {
break true;
}
// Simulate a failed operation,Keep trying
};
println!("Retry {} Success on the next attempt: {}", attempts, success);
}
Output:
Countdown: 5...
Launch!
loopis the only loop structure in Rust that can return a value. A return value can follow thebreakkeyword directly, without the need for an additional variable. This is very useful in the "try-until-successful" pattern.
▶ Example 2: while Conditional Loop (Difficulty ⭐)
Output:
Countdown: 5...
Launch!
// ============================================
// while Loop:Countdown in Decreasing Order
// ============================================
fn main() {
let mut countdown = 5;
while countdown > 0 {
println!("Countdown: {}...", countdown);
countdown -= 1;
}
println!("Launch!");
}
Output:
Countdown: 5...
Countdown: 4...
Countdown: 3...
Countdown: 2...
Countdown: 1...
Launch!
Output:
-- Scope 0..5 --
whileCheck the condition before the start of each iteration. If the condition isfalse, skip the entire loop body. This is suitable for scenarios where "the number of iterations is unknown, but the termination condition is known."
▶ Example 3: Iterating with for and Ranges (Difficulty ⭐⭐)
Output:
-- Scope 0..5 --
<i>
-- Scope 0..=5 --
<i>
-- List of Fruits --
<fruit>
-- Indexed Iteration --
Fruit #<index>: <fruit>
// ============================================
// for Loop:Iteration Range,Arrays and Strings
// ============================================
fn main() {
// 1. Range Iteration: 0..5 is 0 to 4 (Excludes 5)
println!("-- Scope 0..5 --");
for i in 0..5 {
print!("{} ", i);
}
println!();
// 2. Closing Range:0..=5 Includes 5
println!("-- Scope 0..=5 --");
for i in 0..=5 {
print!("{} ", i);
}
println!();
// 3. Iterate through an array
let fruits = ["apple", "banana", "cherry"];
println!("-- List of Fruits --");
for fruit in &fruits {
println!("{}", fruit);
}
// 4. Indexed Iteration(enumerate)
println!("-- Indexed Iteration --");
for (index, fruit) in fruits.iter().enumerate() {
println!("Fruit #{}: {}", index, fruit);
}
}
Output:
-- Scope 0..5 --
0 1 2 3 4
-- Scope 0..=5 --
0 1 2 3 4 5
-- List of Fruits --
apple
banana
cherry
-- Indexed Iteration --
Fruit #0: apple
Fruit #1: banana
Fruit #2: cherry
foris the most recommended way to loop in Rust. It prevents out-of-bounds access and automatically handles iteration.0..nis a half-open interval (excluding n),0..=nis a closed interval (including n)..enumerate()assigns an index to each element.
▶ Example 4: Loop Labels and Nested Loops (Difficulty ⭐⭐⭐)
Output:
Find the Target 5 At the location (<i>, <j>)
Values found: 0
x=<x>, y=<y>
// ============================================
// Loop Label:break 'label Breaking Out of Multiple Levels of Nesting
// ============================================
fn main() {
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
let mut found = 0;
// 'search Outer Loop for Tag Marking
'search: for (i, row) in matrix.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
if val == 5 {
println!("Find the Target 5 At the location ({}, {})", i, j);
found = val;
break 'search; // Exit two nested loops immediately!
}
}
}
println!("Values found: {}", found);
// continue It can also be used in conjunction with tags.
'outer: for x in 0..3 {
for y in 0..3 {
if x == y {
continue 'outer; // Skip the remaining inner layers,Continue to the next outer layer
}
println!("x={}, y={}", x, y);
}
}
}
Output:
Find the Target 5 At the location (1, 1)
Values found: 5
x=1, y=0
x=2, y=0
x=2, y=1
Without a label,
breakandcontinueonly affect the innermost loop. By adding a label ('name), you can control loops at any level. This is a more controlled way to "break out" thangoto.
▶ Example 5: Comprehensive Exercise—FizzBuzz and the Multiplication Table (Difficulty ⭐⭐)
Output:
=== FizzBuzz (1-30) ===
FizzBuzz
Fizz
Buzz
<n>
=== The 9×9 Multiplication Table ===
<i>×<i * j>=<j>
=== while let Simulated Read ===
Encountered a termination signal,Stop Processing
Projects in Progress: <item>
=== loop Retry Mode ===
Connection Results: <attempts>
Attempt #0 to connect...
// ============================================
// Comprehensive Cycle Practice:FizzBuzz + The 9×9 Multiplication Table
// ============================================
fn main() {
println!("=== FizzBuzz (1-30) ===");
for n in 1..=30 {
match (n % 3, n % 5) {
(0, 0) => print!("FizzBuzz "),
(0, _) => print!("Fizz "),
(_, 0) => print!("Buzz "),
_ => print!("{} ", n),
}
if n % 10 == 0 { println!(); }
}
println!();
println!("\n=== The 9×9 Multiplication Table ===");
for i in 1..=9 {
for j in 1..=i {
print!("{}×{}={:<4}", j, i, i * j);
}
println!();
}
println!("\n=== while let Simulated Read ===");
let mut queue = vec![10, 20, 30, 40, 0];
while let Some(item) = queue.pop() {
if item == 0 {
println!("Encountered a termination signal,Stop Processing");
break;
}
println!("Projects in Progress: {}", item);
}
println!("\n=== loop Retry Mode ===");
let attempts = try_connect(3);
println!("Connection Results: {}", attempts);
}
fn try_connect(max_retries: u32) -> bool {
let mut attempt = 0;
loop {
attempt += 1;
println!("Attempt #{} to connect...", attempt);
if attempt >= max_retries {
break true;
}
}
}
Output:
=== FizzBuzz (1-30) ===
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz
11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz
=== The 9×9 Multiplication Table ===
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
=== while let Simulated Read ===
Projects in Progress: 40
Projects in Progress: 30
Projects in Progress: 20
Projects in Progress: 10
Encountered a termination signal,Stop Processing
=== loop Retry Mode ===
Attempt #1 to connect...
Attempt #2 to connect...
Attempt #3 to connect...
Connection Results: true
FizzBuzz is more elegantly implemented using
matchtuple pattern matching; the multiplication table uses a two-levelfor+ range;while letis suitable for handling the "continue as long as a value is retrieved" loop pattern;loop+breakis suitable for retry logic.
❓ FAQ
loop and while true?loop is the preferred choice in Rust.for i in 0..n and for i in 0..=n?.. denotes a half-open interval (excluding n), while ..= denotes a closed interval (including n).into_iter to borrow the elements, while fruits.iter() is more explicit and clearer.break?break statement in a loop can return a value just like a function: let x = loop { break 42; };.📖 Summary
loop: Infinite loop; usebreak valueto return a valuewhile: Conditional loop; checks the condition before each iterationfor: Set/range iteration—highly recommended- Range expressions:
0..5(excluding 5),0..=5(including 5) - The loop tag
'labelcan exit or skip a loop at any level breakExit the loop;continueSkip the remainder of this iteration
📝 Exercises
- Difficulty ⭐: Use
forto iterate through0..=10, printing only even numbers (usingif i % 2 == 0to check). - Difficulty ⭐⭐: Simulate the return value using
loop+break: Find the first value greater than 6 in vec![1, 3, 5, 7, 9, 11] and return it; if none is found, return -1. - Difficulty ⭐⭐⭐: Use a double-layered
forloop to print a 9x9 multiplication table, with each row formatted as1x1=1 1x2=2 …. Think about how to use loop labels to control the line-breaking logic.