Control Flow in Zig
Learn how to control program flow in Zig with if/else expressions, while and for loops, switch statements, and labeled break/continue using Docker-ready examples
Control flow is how a program decides what to do next: which branch to take, how many times to repeat work, and when to stop. Zig keeps this deliberately simple and explicit — there are no hidden jumps, no exceptions unwinding the stack, and no surprising function calls behind an operator. What you read is what runs.
As a multi-paradigm systems language, Zig gives you the familiar structured tools — if, while, for, and switch — but with a twist that distinguishes it from C: most of these constructs are expressions, not just statements. An if or a switch can produce a value, which is why Zig has no ternary operator and rarely needs one. Loops can also yield values through labeled blocks.
In this tutorial you will learn how to branch with if/else, iterate with while and for, dispatch with exhaustive switch statements, and steer loops precisely with break, continue, and labels. Every example is self-contained and runnable with Docker.
Conditionals with if/else
Zig’s if works as both a statement and an expression. Because it can return a value, the pattern const max = if (a > b) a else b; replaces the ternary operator found in other C-family languages. if also has a special form for capturing the contents of an optional.
Create a file named control_flow_if.zig:
| |
Loops: while and for
Zig has two looping keywords. while repeats as long as a condition holds and supports an optional continue expression (: (i += 1)) that runs after every iteration — handy for keeping the update logic in one place. for iterates over arrays, slices, and integer ranges, and can bind an index alongside each element.
Create a file named control_flow_loops.zig:
| |
Switch statements
Zig’s switch is exhaustive: every possible value must be handled, or you must provide an else branch — the compiler enforces it. Arms can match single values, comma-separated lists of values, or inclusive ranges with .... Like if, switch is also an expression, so it can return a value directly.
Create a file named control_flow_switch.zig:
| |
Loop control: break, continue, and labels
break exits a loop early and continue skips to the next iteration. Zig adds a powerful refinement: labels. A labeled block can break with a value, turning a loop into an expression. Labeled loops let break and continue target an outer loop directly, which removes the need for flag variables in nested iterations.
Create a file named control_flow_advanced.zig:
| |
Running with Docker
Run each example with the official Zig image — no local Zig installation required.
| |
Expected Output
control_flow_if.zig:
It's mild
max = 12
got value 42
control_flow_loops.zig:
while: 1
while: 2
while: 3
sum 1..5 = 15
color: red
color: green
color: blue
0 -> red
1 -> green
2 -> blue
range: 0
range: 1
range: 2
control_flow_switch.zig:
Wednesday
score 85 -> grade B
'e' is a vowel
control_flow_advanced.zig:
odd: 1
odd: 3
odd: 5
odd: 7
first > 20: 23
counted pairs: 3
Key Concepts
ifis an expression — Zig has no ternary operator becauseconst x = if (cond) a else b;does the job directly.- Optional capture —
if (optional) |value| { ... }unwraps an optional only when it is non-null, making null handling explicit and safe. - Two loop keywords — use
whilefor condition-driven loops andforto iterate over arrays, slices, and0..ninteger ranges. - Continue expressions — the
while (cond) : (update)form keeps the per-iteration update next to the condition, so the loop body stays focused. - Exhaustive switch — the compiler requires every case to be covered (or an
else), eliminating an entire class of missed-case bugs. - Switch arms are flexible — match single values, value lists (
4, 5), or inclusive ranges (80...89), and letswitchreturn a value as an expression. - Labels are first-class — labeled blocks
breakwith a value, and labeled loops letbreak/continuetarget an outer loop without flag variables. - No hidden control flow — every branch and jump is visible in the source; Zig never inserts implicit function calls or exceptions behind your back.
Running Today
All examples can be run using Docker:
docker pull kassany/alpine-ziglang:0.14.0
Comments
Loading comments...
Leave a Comment