const expect = @import("std").testing.expect;test "if expression" { // If expressions are used instead of a ternary expression. const a: u32 = 5; const b: u32 = 4; const result = if (a != b) 47 else 3089; try expect(result == 47);}test "if boolean" { // If expressions test boolean conditions. const a: u32 = 5; const b: u32 = 4; if (a != b) { try expect(true); } else if (a == 9) { unreachable; } else { unreachable; }}
Zig’s if can be used as an expression, similar to a ternary operator in other languages.
test "if optionals" { var maybe_value: ?i32 = 10; if (maybe_value) |value| { // value is unwrapped here try expect(value == 10); } else { unreachable; }}
Switch expressions in Zig are powerful and must be exhaustive:
const std = @import("std");const builtin = @import("builtin");const expect = std.testing.expect;test "switch simple" { const a: u64 = 10; const zz: u64 = 103; // All branches of a switch expression must be able to be coerced to a // common type. const b = switch (a) { // Multiple cases can be combined via a ',' 1, 2, 3 => 0, // Ranges can be specified using the ... syntax. These are inclusive // of both ends. 5...100 => 1, // Branches can be arbitrarily complex. 101 => blk: { const c: u64 = 5; break :blk c * 2 + 1; }, // Switching on arbitrary expressions is allowed as long as the // expression is known at compile-time. zz => zz, blk: { const d: u32 = 5; const e: u32 = 100; break :blk d + e; } => 107, // The else branch catches everything not already captured. // Else branches are mandatory unless the entire range of values // is handled. else => 9, }; try expect(b == 1);}
Switch expressions can be used outside functions and are compile-time evaluated when the target is known at compile-time.
For loops in Zig iterate over arrays, slices, and ranges:
const expect = @import("std").testing.expect;test "for basics" { const items = [_]i32{ 4, 5, 3, 4, 0 }; var sum: i32 = 0; // For loops iterate over slices and arrays. for (items) |value| { // Break and continue are supported. if (value == 0) { continue; } sum += value; } try expect(sum == 16); // To iterate over a portion of a slice, reslice. for (items[0..1]) |value| { sum += value; } try expect(sum == 20); // To access the index of iteration, specify a second condition as well // as a second capture value. var sum2: i32 = 0; for (items, 0..) |_, i| { try expect(@TypeOf(i) == usize); sum2 += @as(i32, @intCast(i)); } try expect(sum2 == 10); // To iterate over consecutive integers, use the range syntax. var sum3: usize = 0; for (0..5) |i| { sum3 += i; } try expect(sum3 == 10);}
test "multi object for" { const items = [_]usize{ 1, 2, 3 }; const items2 = [_]usize{ 4, 5, 6 }; var count: usize = 0; // Iterate over multiple objects. // All lengths must be equal at the start of the loop. for (items, items2) |i, j| { count += i + j; } try expect(count == 21);}
test "for reference" { var items = [_]i32{ 3, 4, 2 }; // Iterate over the slice by reference by // specifying that the capture value is a pointer. for (&items) |*value| { value.* += 1; } try expect(items[0] == 4); try expect(items[1] == 5); try expect(items[2] == 3);}
test "for else" { const items = [_]?i32{ 3, 4, null, 5 }; // For loops can also be used as expressions. // Similar to while loops, when you break from a for loop, // the else branch is not evaluated. var sum: i32 = 0; const result = for (items) |value| { if (value != null) { sum += value.?; } } else blk: { try expect(sum == 12); break :blk sum; }; try expect(result == 12);}
Use for loops for iteration over collections and while loops for conditional iteration.