Ziglings 笔记 45: 面对虚无 (Optionals)

薛定谔的值

在掌握了错误处理后,Ziglings 的第 45 个练习带我们进入了 Optionals (可选类型) 的世界。

在很多语言中,空指针 (Null Pointer) 是“由十亿美元的错误”。Zig 通过类型系统解决了这个问题:普通的变量永远不能为 null。如果你需要一个可能不存在的值,你必须显式地使用问号 ?

挑战:填补空缺

程序调用了一个名为 deepThought 的函数,它返回一个 ?u8(可能是一个字节,也可能是 null)。 在这个特定的例子中,它很不给面子地返回了 null。我们需要在 main 函数中安全地提取这个值,如果它是 null,则使用默认值 42

解决方案

我们使用 orelse 关键字来处理 null 情况:

const std = @import("std");

pub fn main() void {
    const result = deepThought();

    // 核心语法:orelse
    // 逻辑:尝试读取 result。如果是 null,就用 42 代替。
    // 这将类型从 ?u8 (不确定) 转换为了 u8 (确定)。
    const answer: u8 = result orelse 42;

    std.debug.print("The Ultimate Answer: {}.\n", .{answer});
}

// 返回类型 ?u8 表示:我可能返回一个 u8,也可能什么都不给 (null)
fn deepThought() ?u8 {
    return null;
}

核心知识点总结

1. ?T 语法

任何类型前加上 ? 就变成了可选类型。

  • u32:必须是一个数字。
  • ?u32:是一个数字或者 null

2. orelse vs catch

这两个关键字是 Zig 安全解包机制的“双子星”:

  • catch:用于 Error Union (!T)。处理的是“操作失败”的情况。
  • orelse:用于 Optional (?T)。处理的是“没有值”的情况。

它们的作用是一样的:提供一个保底的默认值,从而让我们能安全地继续执行后续代码。

3. 为什么不直接用 0?

有时候“0”和“没有值”是两码事。比如在统计学中,0 代表数值为零,而 null 代表数据缺失。Zig 的 Optionals 让我们能精确地区分这两种状态。


后续预告:就像 error union 可以配合 if 使用一样,可选类型 ?T 也可以配合 if 使用。下一篇我们将学习 if (optional) |value| 语法。