If Expressions
Zig’sif expressions work with three types: bool, ?T (optionals), and anyerror!T (error unions).
Boolean If
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.If with Optionals
test "if optionals" {
var maybe_value: ?i32 = 10;
if (maybe_value) |value| {
// value is unwrapped here
try expect(value == 10);
} else {
unreachable;
}
}
If with Error Unions
test "if error union" {
const a: anyerror!u32 = 0;
if (a) |value| {
try expect(value == 0);
} else |err| {
_ = err;
unreachable;
}
const b: anyerror!u32 = error.BadValue;
if (b) |value| {
_ = value;
unreachable;
} else |err| {
try expect(err == error.BadValue);
}
// Access the value by reference using a pointer capture.
var c: anyerror!u32 = 3;
if (c) |*value| {
value.* = 9;
} else |_| {
unreachable;
}
}
- Value Capture
- Pointer Capture
if (result) |value| {
// use value
} else |err| {
// handle error
}
if (result) |*value| {
value.* = new_value; // modify through pointer
} else |_| {
// handle error
}
Switch Expressions
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.
Switch at Container Level
const os_msg = switch (builtin.target.os.tag) {
.linux => "we found a linux user",
else => "not a linux user",
};
While Loops
Basic While Loop
const expect = @import("std").testing.expect;
test "while basic" {
var i: usize = 0;
while (i < 10) {
i += 1;
}
try expect(i == 10);
}
While with Continue Expression
test "while with continue" {
var i: usize = 0;
while (i < 10) : (i += 1) {
// continue expression runs after each iteration
}
try expect(i == 10);
}
While with Optional
test "while with optional" {
var maybe_num: ?usize = 10;
while (maybe_num) |num| {
if (num == 0) break;
maybe_num = num - 1;
}
}
Infinite loops are possible - ensure your while condition will eventually become false or use
break.For Loops
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);
}
Multi-Object For
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);
}
For by Reference
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);
}
For with Else
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.
Break and Continue
for (items) |item| {
if (item == target) break; // exit loop
}