Control flow: if, loop, while, for

Rust · Essentials · 10 min

Loops and branches are everyday tools, and Rust's versions are expressions with a few useful twists.

if conditions must be a bool; there is no truthiness, so if count { } on an integer does not compile. Write if count != 0. As an expression, if/else can produce a value as long as both arms have the same type.

Rust has three loops:

  • loop { } repeats forever until break. It is an expression: break value makes the loop evaluate to value, which is a neat way to retry until something succeeds.
  • while cond { } runs while a condition holds.
  • for item in iterable { } walks anything iterable. It is the most common loop and avoids index bugs.

Ranges drive counting loops: 0..5 is 0 to 4, 0..=5 includes 5, and (0..5).rev() counts down. To loop over a collection without consuming it, borrow it: for x in &items. Use for (i, x) in items.iter().enumerate() when you also need the index, instead of indexing manually.

Nested loops can be labelled with a lifetime-like name, 'outer: for ..., so that break 'outer or continue 'outer targets the outer loop.

Since Rust 1.88 the 2024 edition also allows let chains in if and while: if let Some(x) = opt && x > 10 { }. You will meet if let with Option shortly.

There is no C-style for (i = 0; i < n; i++) loop and no ++ operator; use ranges and += 1.

Example

fn main() {
    let items = ["ant", "bee", "cat"];
    for (i, name) in items.iter().enumerate() {
        println!("{i}: {name}");
    }

    let mut n = 27u64;
    let steps = loop {
        // loop is an expression; break returns a value
        if n == 1 { break 0; }
        let mut count = 0;
        while n != 1 {
            n = if n % 2 == 0 { n / 2 } else { 3 * n + 1 };
            count += 1;
        }
        break count;
    };
    println!("steps = {steps}"); // steps = 111

    'outer: for x in 1..=3 {
        for y in 1..=3 {
            if x * y == 4 { println!("found {x}*{y}"); break 'outer; }
        }
    }
}

Remember

  • Conditions must be bool; there is no truthiness
  • for x in &collection and ranges like 0..n replace index loops
  • loop can return a value with break value; labels target outer loops

Watch out for

  • Writing for x in vec and then being surprised the vector was moved; use &vec to borrow.

Check yourself

  1. How many times does the body of `for i in 0..=3 {}` run?
  2. What value does `let v = loop { break 7; };` give `v`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: doc.rust-lang.org/book/ch03-05-control-flow.html