Control Flow
If
Inline Conditional
if x > 0 then "positive" else "non-positive"
if condition then expr else expr — both branches required for inline form.
Multi-Arm Conditional
if followed by a block introduces guard-style arms with =>:
fn classify(x: i64) -> String
if
x > 0 => "positive"
x < 0 => "negative"
else => "zero"
Each arm is condition => body. Use else => for the default case.
Arms can have multi-statement bodies:
fn process(x: i64) -> i64
if
x > 0 =>
let doubled = x * 2
doubled + 1
else => 0
Postfix Conditional
expr if condition — executes expr only if condition is true:
return error.FileNotFound if fd < 0
break if i >= 10
This is the primary guard/early-exit pattern.
Match
Pattern matching with => arms:
fn describe(s: Shape) -> i32
match s
Shape::Square.{ side } => side * side
Shape::Circle.{ r } => r * r
Literal Patterns
match x
0 => "zero"
1 => "one"
_ => "other"
Data Type Patterns
match result
Shape::Square.{ s } => s
Shape::Circle.{ r } => r
Or Patterns
Multiple patterns separated by |:
match x
1 | 2 | 3 => "small"
4 | 5 | 6 => "medium"
_ => "large"
Guards
Add conditions with if after the pattern:
match opt
Some.{ x } if x > 0 => "positive"
Some.{ x } if x < 0 => "negative"
Some.{ _ } => "zero"
_ => "none"
Multi-Statement Arms
match x
0 =>
let result = compute()
result + 1
_ => x
For
for is the only loop construct. All forms support break to exit and return to exit the enclosing function.
Infinite Loop
Bare for loops forever. Use break or return to exit.
for
event := poll()
break if event == quit
handle(event)
Condition (While-Style)
for cond loops while the condition is true.
mut i := 10
for i > 0
i <- i - 1
// i is 0 here
mut sum := 0
mut i := 0
for i < 10
sum <- sum + i
i <- i + 1
// sum is 45
Numeric Range
for i in start..end iterates from start up to (but not including) end. The loop variable i is bound to the current value.
mut sum := 0
for i in 0..10
sum <- sum + i
// sum is 45
Collection Iteration
for x in coll iterates over slices, buffers, and fixed arrays. The loop variable x is bound to each element.
for c in text
process(c)
Collection with Index
for x, i in coll — element first, index second. x is the element type, i is usize.
for c, i in text
if is_lower(c) then
buf[i] <- rotate(c, shift)
else
buf[i] <- c
Nested fixed arrays compose naturally with loops and indexing.
matrix : [2; [3; i32]] = .{
.{ 1, 2, 3 },
.{ 4, 5, 6 }
}
sum : i32 = 0
for row in matrix
for cell in row
sum <- sum + cell
matrix[1][2] <- sum
Collection with Filter
for x in coll where cond — only visits elements where the condition is true. The condition can reference the loop variable.
for c in text where is_lower(c)
idx := (c as i32) - 97
counts[idx] <- counts[idx] + 1
Early Return from Loop
return exits the enclosing function, not just the loop:
find :: fn(buf: []u8, target: u8) -> i32
for x, i in buf
return i as i32 if x == target
-1
Return
return exits the function early with a value:
fn clamp(x: i32, lo: i32, hi: i32) -> i32
return lo if x < lo
return hi if x > hi
x
In error union functions, return error.X wraps the error:
fn read_file(path: []const u8) -> !i32
let fd = open(path.ptr, 0)
return error.FileNotFound if fd < 0
// ...