An optional value cannot be used as the payload type until it is unwrapped.
This is wrong:
const x: ?i32 = 10;
const y: i32 = x; // errorx is not an i32. It is a ?i32.
To get the integer out, test the optional:
const std = @import("std");
pub fn main() void {
const x: ?i32 = 10;
if (x) |value| {
std.debug.print("{d}\n", .{value});
}
}The syntax
if (x) |value| {
...
}means: if x contains a value, bind that value to the name value.
Inside the block, value has type i32, not ?i32.
If the optional is null, the block is skipped.
const std = @import("std");
pub fn main() void {
const x: ?i32 = null;
if (x) |value| {
std.debug.print("{d}\n", .{value});
}
}This program prints nothing.
Use else to handle the missing case:
const std = @import("std");
pub fn main() void {
const x: ?i32 = null;
if (x) |value| {
std.debug.print("value: {d}\n", .{value});
} else {
std.debug.print("no value\n", .{});
}
}The output is:
no valueAn optional can also be unwrapped with orelse.
const std = @import("std");
pub fn main() void {
const x: ?i32 = null;
const y: i32 = x orelse 0;
std.debug.print("{d}\n", .{y});
}The expression
x orelse 0means: use the value inside x if it exists; otherwise use 0.
Here y is an i32.
orelse is useful for defaults:
fn portOrDefault(port: ?u16) u16 {
return port orelse 8080;
}If port has a value, that value is returned. If port is null, the function returns 8080.
There is also a force unwrap operator:
const x: ?i32 = 10;
const y: i32 = x.?;The expression x.? extracts the payload.
It is safe only if x is not null.
This will fail at runtime in safe builds:
const x: ?i32 = null;
const y: i32 = x.?;Use .? only when the program has already proved that the optional is not null.
For example:
const std = @import("std");
pub fn main() void {
const x: ?i32 = 10;
if (x != null) {
const y = x.?;
std.debug.print("{d}\n", .{y});
}
}This works, but the payload capture form is clearer:
if (x) |value| {
std.debug.print("{d}\n", .{value});
}Prefer the capture form when possible. It keeps the proof and the value together.
Exercise 9-8. Write a function valueOrZero that takes ?i32 and returns i32.
Exercise 9-9. Write a function printOptionalName that takes ?[]const u8 and prints either the name or "(none)".
Exercise 9-10. Rewrite a force unwrap with an if capture.