Control Flow

Conditions and loops

let label = if value > 0 { 1 } else if value < 0 { -1 } else { 0 }

let mut index: usize = 0
while index < len(values) {
    index = index + 1
}

for item in values {
    consume_copy(item)
}

if is an expression. while and for support break and continue. for over ranges, arrays, and slices lowers to a direct allocation-free index/length loop. Move-only elements require explicit indexing and ownership handling.

Match and ADTs

enum Response {
    Ok(i64)
    Err(str)
}

fn status(value: Response) -> i64 {
    match value {
        Ok(code) => code
        Err(message) => -1
    }
}

Match arms have no commas and must be exhaustive unless remaining flow is unreachable. Patterns support literals, tuples, structs, variants, bindings, discard, and guards. Move-only payloads transfer only when an arm is selected; a failed pattern or guard preserves the owner for later arms.

Options, results, and ?

fn find(enabled: bool) -> ?i64 {
    if enabled { Some(42) } else { None }
}

fn forward(enabled: bool) -> ?i64 {
    let value = find(enabled)?
    Some(value)
}

? yields the present/success payload or returns the corresponding failure. Result propagation may change success type but preserves error type. No implicit allocation or clone occurs. ? cannot cross a spawn boundary.

Cleanup on flow edges

Fallthrough, return, break, and continue execute the verified cleanup plan for live owners. Panic/trap/abort edges never unwind and run no cleanup.