पाठ 4 / 25
if, while, for, switch and Labelled Blocks
Use Zig's control-flow expressions, including captures and labelled breaks.
Control flow as expressions
if works as a statement or an expression (const fee = if (total >= 100_000) 0 else 4_900;) and can capture the payload of optionals and error unions: if (maybe_user) |user| { ... }. while loops can have a continue expression run after each iteration (while (i < n) : (i += 1)) and can also capture optional payloads, which is how iterators are consumed: while (it.next()) |item|. for loops iterate over arrays, slices and ranges, and since Zig 0.11 can iterate several objects in lockstep, including an index range: for (items, 0..) |item, i|. Capture by pointer (|*item|) to modify elements in place. Loops can have an else branch that runs when they end without break. switch must be exhaustive, supports ranges (1...9), multiple values, else, and captures for tagged unions. Labelled blocks turn a block into an expression: const x = blk: { ...; break :blk value; };, and labelled loops allow break :outer from nested loops. There is no goto and no implicit fallthrough.
Expressions everywhere
if, switch and labelled blocks produce values; loops can capture payloads.
Control flow in practice
Expressions, captures, multi-object for and labelled blocks.
const std = @import("std");
fn shippingFee(total_paise: u64, express: bool) u64 {
return if (total_paise >= 100_000) 0 else if (express) 9_900 else 4_900;
}
fn grade(marks: u8) u8 {
return switch (marks) {
85...100 => 'A',
70...84 => 'B',
40...69 => 'C',
0...39 => 'F',
else => '?', // 101..255 are possible u8 values, so else is required
};
}
pub fn main() void {
const prices = [_]u32{ 4_950, 19_900, 9_900 };
const qtys = [_]u32{ 2, 1, 5 };
var total: u64 = 0;
for (prices, qtys, 0..) |price, qty, i| { // lockstep iteration with an index
std.debug.print("line {d}: {d} x {d}\n", .{ i + 1, qty, price });
total += @as(u64, price) * qty;
}
const first_expensive = blk: {
for (prices, 0..) |p, i| {
if (p > 10_000) break :blk i;
}
break :blk null; // block type is ?usize
};
var countdown: u8 = 3;
while (countdown > 0) : (countdown -= 1) {
std.debug.print("{d}...\n", .{countdown});
}
std.debug.print("total={d} fee={d} grade={c}\n", .{ total, shippingFee(total, false), grade(72) });
if (first_expensive) |idx| std.debug.print("first item over Rs 100 at index {d}\n", .{idx});
}switch on integers needs every value
A switch over a u8 must cover all 256 values, so add an else prong or narrow the type. Switching over an enum or tagged union without else gives you a compile error whenever a new case is added, which is exactly what you want.
त्वरित जाँच: What does `for (items, 0..) |item, i|` do?
- Iterates items twice
- Declares a range of zeros
- Iterates items together with an index starting at 0
- It is invalid syntax
Answer
Iterates items together with an index starting at 0 — Multi-object for loops iterate several sequences in lockstep, here items and an index range.