跳转至

控制流——三种循环和 switch 穿透全是别家的规矩

这一章讲一件事: 原书第四章教程序怎么分叉(if/else)、怎么重复(循环)、 怎么多路选择(switch)。if 那节大体可用;循环和 switch 两节, 你按书敲出来的每一行 Zig 代码都过不了编译。 这一章的收获是双份的: 书里的假语法长什么样,和真实的 Zig 把同一批问题换成了什么设计。

1. 这一章讲什么

原书第四章四节:4.1 条件语句(if / else / else if / 嵌套),4.2 循环 (for / while / do-while),4.3 break 与 continue,4.4 switch(含穿透和防穿透)1。 四节的主题清单本身就是 C 系教材的标准清单——问题从清单开始就是借来的: Zig 的循环和 switch 设计,恰恰是为了不照这套清单走。

2. 顶层全景:书的设计 vs 真实 Zig 的设计

把两边对同一个问题(「打印 0 到 9」)的写法摆在一起:

  书里(4.2 节的 for)                真实 Zig
  ─────────────────────────────────────────────
  for (var i = 0; i < 10; i++) {     for (0..10) |i| {
      std.debug.print(                   std.debug.print("{}\n", .{i});
          "i = {}\n", .{i});         }
  }
      │                                   │
      └─ C 语言的三段式:for(初始化;      └─ 一个范围 0..10,一个循环变量 i,
         条件;步进)。i++ 这个自增             从范围里「接」出来的。
         运算符 Zig 没有。

  图说:同一件事,左边是一行微型状态机,右边是一句「对 0 到 9 里的每个 i」。
  Zig 故意把 for 做成「遍历」的形状,而不是「微型状态机」的形状。

这个对比值得停一下:C 式 for 把三件事(计数器、条件、步进)挤在一行括号里, 是出了名的易错处(少写一个 i 的变化就死循环)。Zig 的 for (0..10) |i| 把计数器管理藏进语言,你只管说「遍历这个范围」。书教的恰恰是 Zig 设计上 要淘汰的那种写法。

3. 核心原理之一:if/else——骨架真,细节假

书教的 if / else if / else 链和嵌套 if,结构和真实 Zig 一致(条件为真走哪支、 否则走下支),例子的逻辑(判断 x 正负零)也通用2。但有一个语法细节要修: 真实 Zig 的 if 条件不用包圆括号(if x > 0 {),书里写的 if (x > 0) { 是 C 习惯——真实 Zig 也接受不了吗?其实 Zig 会报语法错误。 另外真实 Zig 的 if 是表达式(整个 if 能产出值:const y = if (x > 0) 1 else 2;), 还能当类型用——这层能力书完全没提。

顺带解释一个后面要用的词:表达式(expression)指「能算出值的一段代码」, 和它相对的是语句(statement),只做事不产值。书把 if 当语句教, 真实 Zig 把 if 做成表达式——这个差别到错误处理(第 06 章对照)时会再显威力。

再看一个书没教的 if 能力:真实 Zig 的 if 条件可以接可选类型 (?T,「可能没有」的类型,第 03 章边界处提过)—— if (maybe_value) |v| { ... },只有当值真的存在时才走进分支, 并且顺手把值从「可选」里拆出来交给 v。第 08 章会看到这个写法 是 Zig 并发与解析代码里最常用的循环搭档;书的世界观里, 这件事是用「null 检查」这种 C 式语句处理的——又一个「书停在 C」的现场。

4. 核心原理之二:循环——三种里只有一种是 Zig 的

书列了三种循环,逐个对账3:

书里的循环 真实 Zig 有没有 差在哪
C 式三段 for(for (var i = 0; i < 10; i++)) 没有这种写法 Zig 的 for 只用于遍历:for (数组/范围) \|元素\|;i++ 自增运算符在 Zig 里也不存在,要写 i += 1
while(条件为真就重复) 有,基本同 书里的例子几乎能用;Zig 还有 continue 表达式(while (i < 10) : (i += 1)),把步进写在条件后面,书没提
do-while(先跑一遍再看条件) 没有 Zig 根本没有 do-while;「至少执行一次」要用别的写法凑

「选哪种循环」那条指南(知道次数用 for、直到条件满足用 while、至少一次用 do-while) 是 C 教材的标准答案,三个判据里有一个在 Zig 里没有对应物—— 这套指南搬到 Zig 的第一条就要改写成「要遍历用 for,要守着条件用 while」。

5. 核心原理之三:switch——这一节几乎全是反的

书的 4.4 节教 switch:写法是 C 式 switch (expr) { case 1: ... default: ... }, 并且说「在 Zig 里 case 会穿透到下一个,要加 break 防止穿透」4。

对照真实 Zig,这一节几乎每一句都是反的:

  书说                         真实 Zig
  ─────────────────────────────────────────────────
  case 1: / default: 标签      1 => ..., else => ...(箭头,不是冒号)
  分支会穿透(fall through)     永不穿透;每个分支是一个表达式/块
  要 break 防穿透              没有穿透,自然不需要 break
  switch 是语句                switch 是表达式(能产出值)

  图说:四条说法四条反。这是全书单节「含假率」的最高纪录之一。

真实 Zig 的 switch 还有两个书不可能告诉你的设计:

  • 必须穷举:switch 覆盖不了输入的所有可能值,编译直接报错; 覆盖不全就写一个 else 兜底。C 的 switch 漏了分支只是默默跳过,这是无数 bug 的来源。
  • 能当表达式用:const name = switch (day) { 1 => "Mon", ..., else => "?" }; 一行完成查表。

为什么 Zig 敢这么设计? 因为穿透和漏分支的历史代价太大(C 程序的经典漏洞 很多长在 switch 上),而穷举检查在编译期就能做完,不花运行时代价。 这是「性能与安全可以兼得」那句口号的一个具体落点——书在第 01 章抄过这句口号, 到这里本该是它最好的例证,书里却只有反例。

6. 核心原理之四:break 与 continue——词是真的,家教是别人的

break(立即跳出循环)和 continue(跳过本轮、进下一轮)这两个词和基本语义, 真实 Zig 都有,书的两个例子(到 5 就停、跳过偶数)逻辑也通用5。 但有两个细节修正:例子里的 i++ 要改成 i += 1(Zig 没有自增运算符); 书对 break/continue 的告诫(少用、写注释)是 C 圈的家教,在 Zig 里 「用 if 表达式替代 break」是更地道的写法——因为 if 是表达式,很多 需要 break 的场景可以改成条件表达式直接算出来。

7. 作者的判断与证据

  • 可用: if/else 链的逻辑骨架、while 的基本形态、break/continue 的概念。
  • 不可用: C 式三段 for、i++、do-while、case/default 标签、switch 穿透说、 「break 防穿透」的教法和例子345。
  • 证据形态: 全章没有一个例子附过编译输出。真实 Zig 编译器对「for (var i = 0; ...)」 会立刻给出语法错误——这是书里全部循环例子无法运行的直接证明。

8. 边界与局限

  • 书没讲循环里的 for 遍历切片/数组时同时拿下标和元素的写法 (for (items, 0..) |item, i|)——真实 Zig 高频用法。
  • 书没讲 while 与可选类型(?T)配合的模式(while (it.next()) |item|), 这是真实 Zig 里比三种循环都常用的循环形态(官方文档的单词分词例子就是它)—— 分词指把一句话切成一个个词,切完正好一轮处理一个词。6
  • 控制流章的缺席名单(表达式 if、穷举 switch、optional 循环)恰好是 Zig 控制流设计的三根支柱——这个「恰好」就是本书问题的一个缩影: 它对「Zig 为什么不一样」毫无感知。

9. 可带走的

  1. if/else 的逻辑骨架可用,但圆括号是 C 习惯;真实 Zig 里 if 还是表达式,能产出值。
  2. 三种循环只有一种(while)基本对得上;C 式三段 for 和 do-while 都不是 Zig。
  3. Zig 的 for 是「遍历形状」:for (0..10) |i|、for (数组) |元素|。
  4. switch 四条说法四条反:不穿透、用 =>、必须穷举、是表达式。穿透是 C 的规矩,不是 Zig 的。
  5. i++ 在 Zig 里不存在,写 i += 1。
  6. 想见识真实 Zig 控制流的招牌:if 表达式、穷举 switch、while (可选值) |值| 循环——书里没有,去官方文档看。

10. 原文地图

主题 原书章 原文位置
if / else if / else、嵌套条件 Chapter 4 Control Flow text/07-ch04-chapter-4-control-flow.txt:11(搜「used to execute a block of code if a condition is true」) · text/07-ch04-chapter-4-control-flow.txt:71(搜「check additional conditions」) · text/07-ch04-chapter-4-control-flow.txt:113(搜「Nest conditional statements」)
C 式 for、while、do-while Chapter 4 Control Flow text/07-ch04-chapter-4-control-flow.txt:145(搜「three types of loops」) · text/07-ch04-chapter-4-control-flow.txt:155(搜「for (initializer; condition; increment)」) · text/07-ch04-chapter-4-control-flow.txt:209(搜「executes the loop body at least once」)
选循环的指南 Chapter 4 Control Flow text/07-ch04-chapter-4-control-flow.txt:235(搜「Choosing the Right Loop」)
break 与 continue Chapter 4 Control Flow text/07-ch04-chapter-4-control-flow.txt:251(搜「exit a loop prematurely」) · text/07-ch04-chapter-4-control-flow.txt:275(搜「skip the current iteration」)
switch 写法与穿透说 Chapter 4 Control Flow text/07-ch04-chapter-4-control-flow.txt:313(搜「select one of several code blocks」) · text/07-ch04-chapter-4-control-flow.txt:369(搜「fall through to the next case」) · text/07-ch04-chapter-4-control-flow.txt:399(搜「Prevent Fall-Through」)

  1. 出处:「Chapter 4 Control Flow」第 5、143、247、311 段(text/07-ch04-chapter-4-control-flow.txt:5,搜「4.1 Conditional Statements」;:143,搜「4.2 Loops」;:247,搜「4.3 Break and Continue」;:311,搜「4.4 Switch Statements」)。 ↩

  2. 出处:「Chapter 4 Control Flow」第 9–141 段(text/07-ch04-chapter-4-control-flow.txt:11,搜「used to execute a block of code」;:69,搜「check additional conditions」;:111,搜「Nest conditional statements」)。条件链的逻辑骨架通用,圆括号为 C 习惯。 ↩

  3. 出处:「Chapter 4 Control Flow」第 145–245 段(text/07-ch04-chapter-4-control-flow.txt:145,搜「three types of loops」;:155,搜「for (initializer; condition; increment)」;:207,搜「executes the loop body at least once」;:237,搜「Choosing the Right Loop」)。真实 Zig 只有 for(遍历形态)与 while(可带 continue 表达式),无 do-while、无 C 式三段 for、无 i++。 ↩↩

  4. 出处:「Chapter 4 Control Flow」第 311–435 段(text/07-ch04-chapter-4-control-flow.txt:313,搜「select one of several code blocks」;:367,搜「fall through to the next case」;:397,搜「In this example, if the number is equal to 1」)。真实 Zig 的 switch 是表达式、分支用 =>、永不穿透、必须穷举或写 else,见官方语言参考 https://ziglang.org/documentation/master/(查阅于 2026-10-19)。 ↩↩

  5. 出处:「Chapter 4 Control Flow」第 249–309 段(text/07-ch04-chapter-4-control-flow.txt:251,搜「exit a loop prematurely」;:273,搜「skip the current iteration」;:297,搜「judiciously」)。 ↩↩

  6. 补充(不在书里,来自权威外部资料):while (it.next()) |item| 处理可选序列、for 同时取元素与下标的写法,见官方概览的可选类型一节示例(tokenizeAny 例子)。来源:《Overview — Zig Programming Language》https://ziglang.org/learn/overview/(查阅于 2026-10-19)。 ↩