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| 语法。