Rustlers Atom 1.6: Loops: `loop`, `while`, `for`

Rust gives you three looping constructs. There’s no hidden behaviours, no accidental infinite loops, and no implicit coercions. Each kind of loop expresses a specific intent.

loop: The Infinite Primitive

loop is the most fundamental looping construct. It runs forever unless you explicitly stop it with break.

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2; // Break with a value
        }
    };

    println!("Result: {}", result);
}

A loop is an expression, so you can break with a value and assign it to a variable.

If you don’t specify one, the break returns the unit type ().

This is handy for control flow where the exit point isn’t known in advance — like waiting on input, polling, or retrying until success. It’s Rust’s “structured goto”: explicit, visible, and type-checked.

while: Loop While a Condition Holds

while repeats as long as its condition evaluates to true.

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{number}!");
        number -= 1;
    }

    println!("Liftoff!");
}

This feels familiar if you’ve used C, Python, or JavaScript, but with one crucial difference: Rust checks the condition’s type at compile time, and the condition must be a bool.

for: Loop Over Iterators

for is Rust’s most idiomatic loop. It works with anything that implements the Iterator trait — arrays, slices, ranges, or your own iterator types.

fn main() {
    let numbers = [10, 20, 30, 40];

    for num in numbers {
        println!("Number: {num}");
    }

    // Using a range
    for i in 0..5 {
        println!("i = {i}");
    }

    // Exclusive upper bound: 0..5 means 0,1,2,3,4
    // Inclusive: 0..=5 means 0 through 5
}

A for loop takes ownership of the iterator unless you borrow explicitly. This gives you flexibility:

let data = vec!["a", "b", "c"];

// Immutable borrow
for item in &data {
    println!("Item: {item}");
}

// Mutable borrow
for item in &mut data.clone() {
    *item = "x";
}

Loop Labels and Nested Control

You can label loops to control which one you break or continue when nested:

fn main() {
    'outer: for x in 0..3 {
        for y in 0..3 {
            if x == y {
                continue 'outer; // skip to next x
            }
            println!("x = {x}, y = {y}");
        }
    }
}

You'll only receive email when they publish something new.

More from GSLF
All posts