控制流——三种循环和 switch 穿透全是别家的规矩
控制流——三种循环和 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. 可带走的
- if/else 的逻辑骨架可用,但圆括号是 C 习惯;真实 Zig 里 if 还是表达式,能产出值。
- 三种循环只有一种(while)基本对得上;C 式三段 for 和 do-while 都不是 Zig。
- Zig 的 for 是「遍历形状」:
for (0..10) |i|、for (数组) |元素|。 - switch 四条说法四条反:不穿透、用
=>、必须穷举、是表达式。穿透是 C 的规矩,不是 Zig 的。 i++在 Zig 里不存在,写i += 1。- 想见识真实 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」) |
Footnotes
-
出处:「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」)。 ↩ -
出处:「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 习惯。 ↩ -
出处:「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++。 ↩ ↩2 -
出处:「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)。 ↩ ↩2 -
出处:「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」)。 ↩ ↩2 -
补充(不在书里,来自权威外部资料):
while (it.next()) |item|处理可选序列、for同时取元素与下标的写法,见官方概览的可选类型一节示例(tokenizeAny 例子)。来源:《Overview — Zig Programming Language》https://ziglang.org/learn/overview/(查阅于 2026-10-19)。 ↩