Loop Labels
A loop label (or block label) is an identifier prefixed with a single quote ('label) attached to a loop, while, for loop, or plain block { ... }. Passing a loop label to break 'label or continue 'label lets you control a specific outer loop directly from inside deeply nested inner loops.
Loop Label Syntax Rules
A loop label is written immediately before the loop, while, for, or { keyword, followed by a colon (:):
'outer_loop: for row in 0..10 {
─────────── ───
│ └── Loop or block being labeled
└─────────── Label declaration (`'` + snake_case identifier + `:`)
for col in 0..10 {
if done {
break 'outer_loop; // References `'outer_loop` (no colon here!)
}
}
}
| Rule | Details |
|---|---|
| Leading character | Always starts with a single quote/tick ('), just like lifetime names |
| Naming convention | Lowercase snake_case (such as 'search, 'rows, 'outer) |
| Reserved names | Cannot be 'static or '_ |
| Declaration vs Use | Declared with a trailing colon ('outer: loop { ... }), referenced without a colon (break 'outer;) |
Breaking and Continuing an Outer Loop
By default, unlabeled break and continue apply only to the innermost loop. With labels, you can target any enclosing loop:
fn main() {
'rows: for r in 1..=3 {
for c in 1..=3 {
if r == 2 && c == 2 {
println!(" [r={r}, c={c}] -> `continue 'rows` (skipping rest of row 2)");
continue 'rows;
}
if r == 3 && c == 2 {
println!(" [r={r}, c={c}] -> `break 'rows` (exiting both loops completely)");
break 'rows;
}
println!(" Visiting r={r}, c={c}");
}
}
println!("Finished grid traversal.");
}
Visiting r=1, c=1
Visiting r=1, c=2
Visiting r=1, c=3
Visiting r=2, c=1
[r=2, c=2] -> `continue 'rows` (skipping rest of row 2)
Visiting r=3, c=1
[r=3, c=2] -> `break 'rows` (exiting both loops completely)
Finished grid traversal.
'rows: for r in 1..=3 { <-- Target of `continue 'rows` (advances `r`)
for c in 1..=3 {
if r == 2 && c == 2 {
continue 'rows; ------+
}
if r == 3 && c == 2 {
break 'rows; ---------+--+
} |
} |
} |
println!("Finished..."); <-----------+-- Target of `break 'rows`
Returning a Value from a Labeled loop (break 'label value)
When an outer loop is labeled, you can pass both the label and a return value to break (break 'label expr;) from inside an inner loop:
fn find_target_in_3d(cube: &[[[i32; 2]; 2]; 2], target: i32) -> Option<(usize, usize, usize)> {
let mut z = 0;
'search: loop {
if z >= cube.len() {
break 'search None;
}
for y in 0..cube[z].len() {
for x in 0..cube[z][y].len() {
if cube[z][y][x] == target {
// Exits the two `for` loops AND the outer `'search` loop with `Some(...)`!
break 'search Some((z, y, x));
}
}
}
z += 1;
}
}
fn main() {
let data = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]],
];
println!("Coordinates of 7: {:?}", find_target_in_3d(&data, 7));
}
Coordinates of 7: Some((1, 1, 0))
Labeled Plain Blocks ('block: { ... })
Rust also allows attaching a label to a plain block expression ('label: { ... }) that is not a loop at all! Inside a labeled block:
break 'label;orbreak 'label value;is valid and jumps directly to the end of the labeled block (producingvalueas the block's result).continue 'label;is forbidden (E0696), because a plain block only runs once and does not loop.
Labeled blocks are useful when a multi-step calculation inside a function needs an early exit path that should only leave the block rather than returning from the entire function:
fn main() {
let input = " -15 ";
let parsed_positive: u32 = 'parse_step: {
let trimmed = input.trim();
let Ok(num) = trimmed.parse::<i32>() else {
break 'parse_step 0;
};
if num < 0 {
println!("Clamping negative number {num} to 0");
break 'parse_step 0;
}
num as u32
};
println!("parsed_positive = {parsed_positive}");
}
Clamping negative number -15 to 0
parsed_positive = 0
Common Errors and Lints
Referencing an Undeclared or Out-of-Scope Label (E0426)
A label is only in scope inside the body of the loop or block it labels. Referencing a label after its loop has closed or misspelling a label name produces E0426:
// ❌ does not compile
fn main() {
'outer: for i in 0..3 {
for j in 0..3 {
if i + j > 3 {
break 'outre;
}
}
}
}
error[E0426]: use of undeclared label `'outre`
--> src/main.rs:5:23
|
5 | break 'outre;
| ^^^^^^ undeclared label `'outre`
|
help: a label with a similar name exists in this scope
|
5 | break 'outer;
| ~~~~~~
error: aborting due to 1 previous error
Unused Label Warning (unused_labels)
If you attach a 'label: to a loop or block but never reference 'label in any break or continue statement, rustc emits an unused_labels warning:
fn main() {
'unneeded: for i in 0..2 {
println!("{i}");
}
}
warning: unused label
--> src/main.rs:2:5
|
2 | 'unneeded: for i in 0..2 {
| ^^^^^^^^^^
|
= note: `#[warn(unused_labels)]` on by default
Shadowing an Outer Label (shadow_reuse / Compiler Warning)
Using the exact same 'label name on both an outer loop and a nested inner loop causes the inner label to shadow the outer one, making the outer loop unreachable by label name and triggering a compiler warning (label name 'a shadows a label name that is already in scope). Always give nested labeled loops distinct, descriptive names such as 'rows and 'cols.