Ziglings 笔记 30: 必须穷尽的 Switch
严谨的选择
在 Ziglings 的第 30 个练习中,我们遇到了 Switch 语句。 如果你是从 C/C++ 转过来的,你会发现 Zig 的 switch 有点“不近人情”:它不允许你漏掉任何一种可能性。
挑战:未知的字符
程序试图将数字解码为字母(1->A, 2->B…)。但是输入的数组 lang_chars 中包含了一个捣乱的数字 42。
如果我们只写了 1 到 26 的匹配规则,编译器会直接报错:switch must handle all possibilities。
因为输入类型是 u8,它有 256 种可能,我们只处理了不到 30 种,Zig 拒绝编译这种“不完整”的逻辑。
解决方案
为了满足编译器的穷尽性检查(Exhaustiveness Check),我们需要添加一个 else 分支来兜底:
const std = @import("std");
pub fn main() void {
// 26=Z, 9=I, 7=G, 42=?
const lang_chars = [_]u8{ 26, 9, 7, 42 };
for (lang_chars) |c| {
switch (c) {
1 => std.debug.print("A", .{}),
2 => std.debug.print("B", .{}),
// ... 省略中间部分 ...
26 => std.debug.print("Z", .{}),
// 核心修复:
// 添加 else 分支处理所有未明确列出的值 (比如 42)
else => std.debug.print("?", .{}),
}
}
std.debug.print("\n", .{});
}
核心知识点总结
1. 穷尽性检查 (Exhaustiveness)
这是 Zig 安全哲学的体现。
- 优势:如果你以后给一个枚举 (Enum) 添加了新成员,编译器会通过报错提醒你去更新所有相关的
switch语句。这彻底消除了“添加了新状态但忘记处理”这类常见 Bug。 - 对比 C 语言:C 语言的 switch 如果不匹配任何 case 且没有 default,它就什么都不做,悄悄跳过。Zig 认为这是一种隐患。
2. 没有隐式 Fallthrough
Zig 的 switch 不会自动“贯穿”到下一行。
- 你不需要在每个 case 后面写
break。 - 如果你确实想让多个值执行同一段代码,可以使用逗号分隔:
1, 3, 5 => print("Odd")。
3. 表达式语法
虽然本例中 switch 被用作语句(Statement),但它其实也可以用作表达式(Expression)并返回值:
const char = switch (num) {
1 => 'A',
2 => 'B',
else => '?',
};
后续预告:基本的 Switch 用法很简单,但它的能力远不止于此。下一篇我们将看看如何在一个分支里匹配多个值,或者使用范围匹配(Range)。