7.3 Loops
Rust offers several looping constructs, some of which are similar to C’s, while others (like loop
) have no direct C counterpart. Rust also lacks a do-while
loop, but you can emulate that behavior using loop
combined with condition checks and break
.
7.3.1 The loop
Construct
loop
creates an infinite loop unless you explicitly break out of it:
fn main() { let mut count = 0; loop { println!("Count is: {}", count); count += 1; if count == 5 { break; } } }
Key Points:
- Infinite by Default: You must use
break
to exit. - Expression-Friendly: A
loop
can return a value viabreak
.
Loops as Expressions
fn main() { let mut count = 0; let result = loop { count += 1; if count == 10 { break count * 2; } }; println!("The result is: {}", result); }
When count
reaches 10, the break
expression returns count * 2
(which is 20) to result
.
7.3.2 The while
Loop
A while
loop executes as long as its condition evaluates to true
. This mirrors C’s while
loop but enforces Rust’s strict type safety by requiring a boolean condition—implicit conversions from non-boolean values are not allowed.
Basic while
Loop Example
fn main() { let mut count = 0; while count < 5 { println!("Count is: {}", count); count += 1; } }
This loop runs while count < 5
, incrementing count
on each iteration.
while
as an Expression
In Rust, loops can return values using break expr;
. Thus, a while
loop can serve as an expression that evaluates to a final value when exiting via break
.
Example: Using while
as an Expression
fn main() { let mut n = 1; let result = while n < 10 { if n * n > 20 { break n; // The loop returns 'n' when this condition is met } n += 1; }; println!("Loop returned: {:?}", result); }
Here, the while
loop assigns a value to result
. When n * n > 20
, the loop exits via break n;
, making result
hold the final value of n
.
7.3.3 The for
Loop
Rust’s for
loop iterates over ranges or collections rather than offering the classic three-part C-style for
loop:
fn main() { for i in 0..5 { println!("i is {}", i); } }
Key Points:
- Range Syntax:
0..5
includes 0, 1, 2, 3, and 4, but excludes 5. - Inclusive Range:
0..=5
includes 5 as well. - Iterating Collections: You can directly iterate over arrays, vectors, and slices.
fn main() { let numbers = [10, 20, 30]; for number in numbers { println!("Number is {}", number); } }
7.3.4 Labeled break
and continue
in Nested Loops
Rust allows you to label loops and then use break
or continue
with these labels, which is particularly handy for nested loops:
fn main() { 'outer: for i in 0..3 { for j in 0..3 { if i == j { continue 'outer; } if i + j == 4 { break 'outer; } println!("i = {}, j = {}", i, j); } } }
- Labels: Defined with a leading single quote (for example,
'outer
). - Targeted Control:
break 'outer;
stops the outer loop, whilecontinue 'outer;
skips to the next iteration of the outer loop.
In C, achieving similar behavior often requires extra flags or the use of goto
, which can be less clear and more error-prone.