Optionals
Optionals
let us represent missing values. For example, ?u64 means
“either a u64 or null”:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
var opt: ?u64 = null;
print("opt is {?}\n", .{opt});
opt = 4;
print("opt is {?}\n", .{opt});
}$ zig run optionals.zig
opt is null
opt is 4
We can can use .? to get an optional’s value, but that’s
checked illegal behavior in case of
null. We can use an if statement to handle
both cases:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
const opt: ?u64 = 4;
print("opt is {d}\n", .{opt.?});
if (opt) |value| {
print("got value: {}\n", .{value});
} else {
print("got null\n", .{});
}
}$ zig run if.zig
opt is 4
got value: 4
The orelse keyword replaces a null with a
default value:
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
var opt: ?u64 = null;
print("opt or zero: {}\n", .{opt orelse 0});
opt = 4;
print("opt or zero: {}\n", .{opt orelse 0});
}$ zig run orelse.zig
opt or zero: 0
opt or zero: 4
If we use an optional as the expression in a while loop, the loop
ends when the value becomes null:
const std = @import("std");
const print = std.debug.print;
pub fn main() void {
while (countdown()) |n|
print("{}\n", .{n});
print("Go!\n", .{});
}
var counter: u64 = 3;
fn countdown() ?u64 {
if (counter == 0)
return null;
counter -= 1;
return counter + 1;
}$ zig run while.zig
3
2
1
Go!
Next example: Structs.