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)。