GGistDev

Control Flow in Rust

Rust offers expressive control constructs: if, match, loops (loop, while, for), and labels for fine-grained flow.

if / else if / else

Conditions must be bool (no implicit truthiness). if is an expression that can produce a value.

let x = 0;
let sign = if x < 0 { "neg" } else if x == 0 { "zero" } else { "pos" };

match (exhaustive)

match compares a value against patterns; it must be exhaustive.

let status = 404;
let kind = match status {
    200 | 201 => "ok",
    400 => "bad_request",
    404 => "not_found",
    _ => "other",
};

Destructure and guard with if.

let point = (0, 3);
let axis = match point {
    (0, y) => "y",
    (x, 0) => "x",
    (x, y) if x == y => "diag",
    _ => "plane",
};

loop / while / for

loop repeats forever until break; while checks a condition; for iterates over iterators.

let mut n = 3;
while n > 0 { n -= 1; }

for v in [10, 20, 30] { /* v */ }

// loop with value via break
let res = loop { break 42; };

break and continue with labels

Label outer loops to break/continue them from inner loops.

'outer: for i in 0..3 {
    for j in 0..3 {
        if i == j { continue 'outer; }
    }
}

if let / while let (convenience)

Shorthand for matching one pattern.

if let Some(v) = Some(10) { /* use v */ }

let mut it = (0..3).into_iter();
while let Some(v) = it.next() { /* ... */ }

Result and early returns

Use ? to propagate errors, keeping control flow flat.

fn read_first_line(path: &str) -> std::io::Result<String> {
    let file = std::fs::File::open(path)?;
    let mut buf = std::io::BufReader::new(file);
    let mut s = String::new();
    buf.read_line(&mut s)?;
    Ok(s)
}

Summary

  • if is an expression; conditions are boolean only
  • Prefer match for exhaustive branching; destructure and guard with if
  • Use for over iterators; label loops for nested control; ? keeps error paths clear