Loop Expressions
While Loops
A while loop repeatedly executes its body while a condition is true.
while_expr = "while" expression "{" block "}" ;
The condition expression MUST have type bool.
A while expression has type ().
The condition is evaluated before each iteration. If it is true, the body is executed and the condition is re-evaluated. If it is false, the loop terminates.
fn main() -> i32 {
let mut sum = 0;
let mut i = 1;
while i <= 10 {
sum = sum + i;
i = i + 1;
}
sum // 55
}
Infinite Loops
An infinite loop repeatedly executes its body unconditionally.
loop_expr = "loop" "{" block "}" ;
A loop expression that contains no break targeting it has type ! (never), because it never produces a value.
The only way to exit a loop is via break or return.
fn main() -> i32 {
let mut x = 0;
loop {
x = x + 1;
if x == 5 {
break;
}
}
x // 5
}
The loop expression is preferred over while true for infinite loops:
// Preferred
loop {
// ...
}
// Also valid, but less idiomatic
while true {
// ...
}
Break and Continue
The break expression exits the innermost enclosing loop.
The continue expression skips to the next iteration of the innermost enclosing loop.
Both break and continue MUST appear within a loop. Using them outside a loop is a compile-time error.
Both break and continue have the never type !.
A loop expression that contains a break targeting it has type (): executing the break exits the loop, which then evaluates to (). This holds even if the break is unreachable.
Currently, break does not carry a value. A break expression MUST NOT have a value operand; break expr is a compile-time error.
fn main() -> i32 {
let mut x = 0;
while true {
x = x + 1;
if x == 5 {
break;
}
}
x // 5
}
fn main() -> i32 {
let mut sum = 0;
let mut i = 0;
while i < 10 {
i = i + 1;
if i % 2 == 0 {
continue; // skip even numbers
}
sum = sum + i;
}
sum // 25 (1+3+5+7+9)
}
Nested Loops
In nested loops, break and continue affect only the innermost enclosing loop.
fn main() -> i32 {
let mut total = 0;
let mut outer = 0;
while outer < 3 {
let mut inner = 0;
while true {
inner = inner + 1;
total = total + 1;
if inner == 2 {
break; // exits inner loop only
}
}
outer = outer + 1;
}
total // 6
}
For Loops
A for loop iterates over a built-in iterable, binding each element in turn and executing its body once per element. for is a preview feature (enabled with --preview for_loops; see ADR-0037).
for_expr = "for" ( identifier | "_" ) "in" expression "{" block "}" ;
The iterable expression MUST be one of the following, which determine the element type and iteration order:
- an array
[T; N]— each element of typeTis bound in ascending index order; - a
String— each byte is bound asu8in ascending byte order; - the character view
s.chars()of aString— each Unicode scalar value is bound asu32, in ascending byte order (ors.chars_lossy(), which decodes invalid UTF-8 toU+FFFDinstead of trapping).
A for expression has type (). Iteration is a shared read: the collection is borrowed for the duration of the loop and remains usable afterward, and elements are not moved out of it.
break and continue inside a for body affect the for loop as the innermost enclosing loop. continue proceeds to the next element; break terminates the loop.
Iterating s.chars() decodes the bytes of s as UTF-8. A byte sequence that is not well-formed UTF-8 traps at runtime when it is decoded (see ADR-0035). Iterating the lossy view s.chars_lossy() instead substitutes U+FFFD for each ill-formed subsequence and never traps.
fn main() -> i32 {
let a: [i32; 3] = [10, 20, 30];
let mut sum = 0;
for x in a {
sum = sum + x;
}
sum // 60
}