Control Flow
7.1 if
if (x > 0) {
std.debug.print("positive\n", .{});
} else if (x < 0) {
std.debug.print("negative\n", .{});
} else {
std.debug.print("zero\n", .{});
}
const abs = if (x < 0) -x else x; // if as an expression (the ternary)
// if with optionals: unwrap with a payload capture
if (maybe_value) |v| {
std.debug.print("got {d}\n", .{v});
} else {
std.debug.print("null\n", .{});
}
// if with error unions
if (parse(input)) |n| {
use(n);
} else |err| {
std.debug.print("error: {}\n", .{err});
}7.2 switch
const msg = switch (code) {
200 => "OK",
301, 302 => "Redirect",
400...499 => "Client error", // inclusive range
500...599 => "Server error",
else => "Unknown",
};
switch (shape) { // on a tagged union: payload capture
.circle => |r| std.debug.print("circle {d}\n", .{r}),
.rect => |dims| std.debug.print("{d}x{d}\n", .{ dims.w, dims.h }),
}
// switch must be exhaustive (enums/unions don't need else if all cases are covered)
// `inline else` generates a branch per case at comptime
switch (value) {
inline else => |v, tag| std.debug.print("{s}: {any}\n", .{ @tagName(tag), v }),
}7.3 Labeled Switch (0.14+): State Machines
This compiles to efficient jump tables, which is ideal for interpreters and lexers.
state: switch (State.start) {
.start => continue :state .middle, // jump directly to another prong
.middle => if (done) continue :state .end else continue :state .middle,
.end => {},
}7.4 while Loops
var i: usize = 0;
while (i < 10) : (i += 1) { // continue expression runs after each iteration
if (i == 3) continue;
if (i == 8) break;
}
while (iterator.next()) |item| { // loop until null (optional payload)
process(item);
}
while (reader.readByte()) |byte| { // error-union loop
_ = byte;
} else |err| {
if (err != error.EndOfStream) return err;
}
const found = while (i < items.len) : (i += 1) { // while as an expression
if (items[i] == target) break true;
} else false;7.5 for Loops
const items = [_]i32{ 10, 20, 30 };
for (items) |item| std.debug.print("{d}\n", .{item});
for (items, 0..) |item, idx| std.debug.print("{d}: {d}\n", .{ idx, item }); // with index
for (0..5) |n| std.debug.print("{d} ", .{n}); // range (exclusive end)
for (a, b) |x, y| std.debug.print("{d}\n", .{x + y}); // multi-object (same length)
var arr = [_]i32{ 1, 2, 3 };
for (&arr) |*elem| elem.* *= 2; // mutate via pointer capture
const has_neg = for (items) |v| {
if (v < 0) break true;
} else false;7.6 Labels, break, continue
outer: for (0..10) |i| {
for (0..10) |j| {
if (i * j == 42) break :outer;
if (j > i) continue :outer;
}
}7.7 inline for / inline while
const types = .{ u8, u16, u32 };
inline for (types) |T| { // unrolled at compile time
std.debug.print("{s}: {d} bytes\n", .{ @typeName(T), @sizeOf(T) });
}7.8 unreachable
const val = switch (x % 2) {
0 => "even",
1 => "odd",
else => unreachable, // asserts this can't happen (panic in safe modes, UB in fast modes)
};