跳转至

第一个程序 — 学习曲线的真相,和「hello world 一点都不简单」

这一章讲什么: 第 1 章的后五节做三件小事和一件大事。 三件小事:给挫败感打预防针、给三条防滑建议、列一张「Zig 适合干什么」的清单。 一件大事:把两行打印程序拆开给你看——为什么跨平台地往终端打一行字, 实际上牵着进程、文件句柄、缓冲、错误四条线,而 Zig 要你自己把每条线都接住。 读完你会第一次具体看见「显式」这个价值观在代码里的样子。

1. 这一章讲什么

1.4 节是一句预警:Zig 教起来有个麻烦——它太精简了,没多少语法可讲; 但它对「每件事都显式写出」的执念是双刃剑,新手必须为每个语句和表达式负责, 否则「编译器会抱起手臂生闷气」1。

1.5 节给三条防滑建议(读报错、用调试器、用 zig fmt)。 1.6 节写第一个程序——而且立刻推翻它,把「hello world 很简单」这个 流传几十年的说法拆穿。 1.7 节列了九个 Zig 发挥出色的领域。1.8 节是第 1 章的压缩总结。

2. 顶层全景:一个程序的「水下部分」

  你写的两行代码:打印一句话
      │
      ├─ 水面之下 ①:操作系统给你建进程,发三个句柄(stdin / stdout / stderr)
      ├─ 水面之下 ②:语言的运行时先做初始化,然后才调用你的 main
      ├─ 水面之下 ③:输出不是逐字节发的,是先攒在缓冲区、再一次写出(flush)
      └─ 水面之下 ④:每一步都可能失败 —— 谁处理失败?

  图说:1.6 节做的事,就是把这四根线从水里拽出来。
  别的语言把这四根线藏在水下;Zig 让你自己接。

3. 核心原理

3.1 预防针:极简语言为什么反而难学

作者指出的悖论很准确:Zig 是精心构造的极简语言,语法特性少、没有晦涩角落2; 但正因为没有「语法糖」可吃,你唯一的学习障碍就是它要求你负责的每一件事。 1.4 节的原文说:「你必须为每个语句和表达式负责,否则编译器会——打个比方—— 抱起手臂生闷气」1。

他给的出路不是硬扛:「我们会在全书反复回到关键主题。如果某个概念没消化, 我鼓励你先往前翻,带着更多知识和新视角再回来。」3

3.2 三条防滑建议(1.5 节)

① 先读报错,再哭。 从弱类型、少检查的语言转来的人,最容易被编译错误激怒, 觉得代码「喜怒无常又爱吵架」。但 Zig 的报错虽然术语密集,「设计目的是帮你的」: 它报告它实际看到的东西,甚至常给出准确的修法建议。 关键的一句经验法则:「多数情况下,代码一旦编过,就按你预期的那样工作」4。

② 用调试器。 调试器就是用来精确弄清「这段代码此刻在干什么」的工具—— 哪怕你确信这段代码没 bug。不确定某行在做什么,就用调试器去看。 Zig 与 lldb、gdb 以及任何支持 DWARF 标准调试格式的调试器配合良好5。

DWARF 是什么:一种调试信息的标准格式,编译器把你的代码里的变量名、行号 编译进二进制,调试器靠它把机器状态翻译回你看得懂的样子。 (补充,不在书里,来自通用知识。)

③ 用 zig fmt。 Zig 只有一个代码格式化工具,编译器自带,命令是 zig fmt6。 短期收益:不用管格式、少犯语法错;长期收益:所有人的代码一个样子, 你读别人的代码、别人帮你调代码,都少一层障碍。 这一条其实和第 1 章「单一强制风格」的设计决策(见 02 篇)是同一件事的 「工具侧」和「文化侧」。

3.3 主线例子:两行打印程序的水下部分(1.6 节)

这一章的主线例子就是这两版 hello world。 原书给的第一个版本极简:

const std = @import("std");

pub fn main() void {
    std.debug.print("All your codebase are belong to us!", .{});
}

别被示例文案分心(它是 2000 年代初一个游戏翻译梗7)。重点是: @import("std") 引入标准库;main 是程序入口,返回 void(没有返回值); std.debug.print 是「调试打印」——原书特别交代: std.debug 是命名空间,print 是里面的函数8。

然后作者立刻「认罪」:「我也许有点误导了你——或者参与了关于 hello world 程序的 一场巨大造谣运动」9。跨平台地往终端打一行字,需要的不止一个函数。 原书把水下部分拆成三步10:

  第 ① 步 操作系统给你建一个进程,并发三个句柄:
           Unix 类系统叫 stdin / stdout / stderr —— 读从 stdin 读,
          写往 stdout 或 stderr 写;Windows 有对应的句柄
           (句柄 = 操作系统的资源标识,名字起得像「你摸不到的那排抽屉的编号」)
  第 ② 步 操作系统先调你程序里的初始化代码(语言运行时的 setup),
           初始化完了才调你的 main
  第 ③ 步 你的 main 往 stdout/stderr 写字节;但发送数据有延迟,
           所以多数运行时会先攒着 —— 这叫缓冲(buffering);
           攒到条件满足再一次写出,这叫 flush(冲刷)。
           「自动缓冲」正是一种隐式行为,是 Zig 的大忌。
           Zig 的要求:自己带缓冲。

于是第二个版本把每一根线都接到明面上(原书 listing 1.2):

pub fn main() !void {                              // 返回类型改成「!void」:
                                                  // 要么返回空,要么返回一个错误
    const stdout_file = std.fs.File.stdout();     // 拿到 stdout 的文件句柄

    var stdout_buffer: [1024]u8 = undefined;      // 自己声明一个 1024 字节的缓冲区
    var stdout_writer = stdout_file.writer(&stdout_buffer);
                                                  // writer:用上面那个缓冲区,
                                                  // 记住「攒到什么时候该冲」的状态
    const stdout = &stdout_writer.interface;      // interface:通用的「写」接口
    try stdout.writeAll("All your codebase still belong to us!");
                                                  // 写。可能失败 → 必须 try:
                                                  // 失败就把错误交出去
    try stdout.flush();                           // 冲刷:真正把缓冲区内容发给终端
                                                  // 忘写这行,什么都不打印!
}

这个版本里,每个机制在主线例子上占一步:

步骤 机制 具体状态
!void 错误必须进类型 返回类型明说「可能失败」
[1024]u8 = undefined 自带缓冲 1024 字节的暂存区,内容未定
try 错误必须被接住 失败就返回错误给调用方
flush() 显式冲刷 不冲,输出永远停在缓冲区里

注释里「不 flush 就不打印」不是夸张:writeAll 只是把字节拷进你那个 1024 字节的 数组,真正发到终端的是 flush 那一步。

一个版本号警告。 原书示例以 Zig 0.15.1 为准(作者写作时的最新稳定版), std.fs.File.stdout().writer(&buffer) 这套 API 是很新的写法—— 在更早的 0.14 里并不存在。Zig 还没发 1.0,版本间 API 破坏性变更不少, 拿书里代码跑之前先 zig version 核一下11。

3.4 「Zig 适合干什么」九领域(1.7 节)

1.7 节是一张清单,每领域给的理由其实都回指第 1 章的三张牌:C 互操作、编译期保证、 分配器控制。压缩成表:

领域 书里给的理由(全部回指前面的机制)
系统库 C ABI 兼容、类型系统消 bug、编译器检查的错误处理、密封跨平台构建12
嵌入式与操作系统 与硬件交互的全套工具;交叉编译能为任何真机或模拟机写测试
服务器与守护进程 「隐形、可靠、省资源」;崩了就是 showstopper——所以崩溃策略是设计出来的13
编译器/解释器/语言工具 Zig 编译器本身就是用 Zig 写的、速度数一数二;Roc 语言靠 Zig 撑编译器的关键部分;Buzz、Cyber 这类可嵌入脚本语言也选它14
插件与嵌入 会讲 C、静态链接——给 Python/Ruby 写优化库、给 Unity 写插件
WebAssembly 跨的不只是操作系统,还有浏览器;静态链接 + 小二进制15
游戏与引擎 榨干消费级硬件、紧贴 OS API、在紧时间窗内稳定算完;「这是它的看家本领」16
桌面/移动应用 框架有 C 接口就能集成;但对不追求优化的 GUI 是杀鸡用牛刀17
科学数据处理 海量数据下细控内存与文件格式;作者学术工作里的第一选择18

这张表读法上有个窍门:九行理由各不相同,但机制只有三个。 凡是理由里出现「C」「ABI」「静态链接」的,卖的是互操作; 出现「崩溃」「可靠」「保证」的,卖的是编译期检查; 出现「资源」「缓冲」「性能」的,卖的是分配器与显式控制。

3.5 第 1 章总结(1.8 节)

原书的压缩版六条,两句就能转述:Zig 是为想用工业级库写有用代码的系统程序员造的; 它的四张牌是 C 互操作、严格静态保证、世界级元编程(comptime)、 精心设计的内存语义,而且「从不牺牲简单」19。构建系统被单独点名: 「杀手级特性之一」——多语言、跨平台、开箱即用的交叉编译、密封构建、 可复现的包管理,全在一个优化过的包里20。

4. 作者的判断与证据

判断 是书里给的证据,还是作者的推测
「代码一旦编过,就按预期工作」 作者的经验陈述,没有数据,但与「强检查语言故障率低」的行业共识方向一致
hello world 依赖大量隐藏代码 可验证的事实(三步拆解每一步都能拿 OS 文档对)
九领域清单 观点 + 举例(Roc/Buzz/Cyber 是实例),「最适合」的程度没有对照
1.8 总结的「杀手级特性」 社区共识修辞,构建系统是否「killer feature」见仁见智

5. 边界与局限

  • 三步拆解省略了 Windows 与 Unix 的差异细节(原书一句话带过), 读者真要写跨平台 IO 还得回标准库文档。
  • 1.7 节的九领域是 2026 年的快照:WebAssembly、嵌入式这些领域的工具链 变得很快,清单的「时效」比机制讲解短得多。
  • 「用调试器」这条建议对纯新手有台阶缺失:书里没讲调试器怎么装、怎么 接到 zig run 启动的程序上,只说了「你的编辑器多半有原生支持」。
  • hello world 两版代码强绑定 Zig 0.15.1 的 std API,换版本要先核。

6. 可带走的

  1. 极简语言的难点不在语法少,而在没有糖吃——每件显式的事都是你的责任;
  2. 卡住了往前翻,别在原地硬磕——作者自己这么建议;
  3. 「先读报错,再哭」:Zig 报错的术语密度高,但多数是「它看见了什么 + 建议怎么改」;
  4. hello world 的水下四线:进程与三个句柄、运行时初始化、缓冲与 flush、错误;
  5. writeAll 只进缓冲区,flush 才上终端——忘 flush 是最经典的「程序没输出」;
  6. !void 和 try 是成对的:返回类型承诺了可能失败,调用处就必须接住;
  7. zig fmt 不只是格式工具,是「所有人代码一个样子」的协作协议;
  8. 九领域清单的机制只有三张牌:C 互操作、编译期保证、分配器控制—— 拿这三张牌可以推任何新领域适不适合 Zig。

7. 原文地图

主题 原书章 原文位置
极简语言的悖论 1.4 Learning Zig without frustration text/07-ch01-04-1-4-learning-zig-without-frustration.txt:3(搜「minimalistic language」) · text/07-ch01-04-1-4-learning-zig-without-frustration.txt:9(搜「double-edged sword」)
编译器「抱臂生闷气」 1.4 Learning Zig without frustration text/07-ch01-04-1-4-learning-zig-without-frustration.txt:10(搜「cross its arms」)
先读报错,再哭;编过即预期工作 1.5 Just Don’t Get Stuck! It’s That Easy text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:12(搜「Read errors before you weep」) · text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:17(搜「jargon-heavy」) · text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:20(搜「once the code compiles」)
调试器与 DWARF 1.5 Just Don’t Get Stuck! It’s That Easy text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:26(搜「use a debugger」) · text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:27(搜「DWARF」)
zig fmt:唯一格式化工具 1.5 Just Don’t Get Stuck! It’s That Easy text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:32(搜「zig fmt」)
Zero Wing 梗与第一版程序 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:31(搜「Zero Wing」)
zig run 的定位 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:69(搜「zig run will compile」)
std.debug 是命名空间 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:63(搜「std.debug is a namespace」)
「造谣运动」:hello world 不简单 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:74(搜「misinformation campaign」)
水下三步:进程与三个句柄 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:85(搜「three file handles」) · text/09-ch01-06-1-6-how-does-zig-feel.txt:86(搜「stdin, stdout, and stderr」)
缓冲与 flush;自带缓冲 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:98(搜「flushing the buffer」) · text/09-ch01-06-1-6-how-does-zig-feel.txt:100(搜「bring your own buffer」)
版本口径:Zig 0.15.1 1.6 How does Zig feel? text/09-ch01-06-1-6-how-does-zig-feel.txt:40(搜「Zig 0.15.1」)
系统库与 C ABI 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:49(搜「C ABI」)
服务器:隐形可靠,崩溃是 showstopper 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:65(搜「invisible, dependable」) · text/10-ch01-07-1-7-applying-zig.txt:66(搜「showstopper」)
Roc / Buzz / Cyber 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:76(搜「Roc」) · text/10-ch01-07-1-7-applying-zig.txt:79(搜「Buzz」)
WebAssembly 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:94(搜「most excited」)
游戏是看家本领;GUI 是杀鸡用牛刀 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:107(搜「bread and butter」) · text/10-ch01-07-1-7-applying-zig.txt:110(搜「overkill for GUIs」)
学术数据处理 1.7 Applying Zig text/10-ch01-07-1-7-applying-zig.txt:116(搜「In my academic work」)
第 1 章总结:四张牌 1.8 Summary text/11-ch01-08-1-8-summary.txt:4(搜「seamless C interoperability」)

  1. 出处:「1.4 Learning Zig without frustration」第 8–11 段(text/07-ch01-04-1-4-learning-zig-without-frustration.txt:9,搜「double-edged sword」;:10,搜「cross its arms」)。原文:「Zig's absolute dedication to explicitly specifying every bit of behavior is a double-edged sword for those new to the language. You simply must take responsibility for every statement and expression or else the compiler will figuratively cross its arms and pout.」 ↩↩

  2. 出处:「1.4 Learning Zig without frustration」第 1–7 段(text/07-ch01-04-1-4-learning-zig-without-frustration.txt:3,搜「minimalistic language」)。原文:「The problem with teaching the basics of Zig is that Zig is a carefully constructed, minimalistic language. On one hand, there are few syntax features to understand.」 ↩

  3. 出处:「1.5 Just Don’t Get Stuck! It’s That Easy」第 1–6 段(text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:6,搜「fresh perspective」)。原文:「If a concept isn't clicking, I encourage you to move on and return to the material later, armed with more knowledge and a fresh perspective.」 ↩

  4. 出处:「1.5 Just Don’t Get Stuck! It’s That Easy」第 13–21 段(text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:17,搜「jargon-heavy」;:20,搜「once the code compiles」)。原文:「Although Zig's error messages can be jargon-heavy, they're designed to help you.」「More often than not, once the code compiles, it works as you expected.」 ↩

  5. 出处:「1.5 Just Don’t Get Stuck! It’s That Easy」第 23–29 段(text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:27,搜「DWARF」)。原文:「Zig integrates nicely with lldb, gdb, and any other debugger that supports the standard DWARF debugging format.」 ↩

  6. 出处:「1.5 Just Don’t Get Stuck! It’s That Easy」第 31–41 段(text/08-ch01-05-1-5-just-don-t-get-stuck-it-s-that-easy.txt:32,搜「zig fmt」)。原文:「Zig has one single code formatter, included as the compiler subcommand zig fmt.」 ↩

  7. 出处:「1.6 How does Zig feel?」第 29–34 段(text/09-ch01-06-1-6-how-does-zig-feel.txt:31,搜「Zero Wing」)。原文:「'All your codebase are belong to us' is a reference to an early 2000s internet meme, in which the phrase 'All your base are belong to us' appears in a poorly translated release of the game Zero Wing.」 ↩

  8. 出处:「1.6 How does Zig feel?」第 63–65 段(text/09-ch01-06-1-6-how-does-zig-feel.txt:63,搜「std.debug is a namespace」)。原文:「std.debug is a namespace that contains helpful code for us to debug our programs, and print is a function within that namespace.」 ↩

  9. 出处:「1.6 How does Zig feel?」第 74–79 段(text/09-ch01-06-1-6-how-does-zig-feel.txt:74,搜「misinformation campaign」;:77,搜「hidden code」)。原文:「I may have misled you a little — or participated in a giant misinformation campaign about the 'Hello, world!' program in general.」「That program we just wrote relies on a lot of hidden code to make it run.」 ↩

  10. 出处:「1.6 How does Zig feel?」第 83–100 段(text/09-ch01-06-1-6-how-does-zig-feel.txt:85,搜「three file handles」;:98,搜「flushing the buffer」;:100,搜「bring your own buffer」)。三步为原文编号 1–3 的完整列表。 ↩

  11. 出处:「1.6 How does Zig feel?」第 39–46 段(text/09-ch01-06-1-6-how-does-zig-feel.txt:40,搜「Zig 0.15.1」)。原文:「this book can't be updated nightly — so I've chosen to stick with Zig's latest stable release at the time of writing. Currently, this means Zig 0.15.1.」 ↩

  12. 出处:「1.7 Applying Zig」第 45–55 段(text/10-ch01-07-1-7-applying-zig.txt:49,搜「C ABI」;:54,搜「hermetic cross-platform」)。 ↩

  13. 出处:「1.7 Applying Zig」第 64–70 段(text/10-ch01-07-1-7-applying-zig.txt:65,搜「invisible, dependable」;:66,搜「showstopper」)。 ↩

  14. 出处:「1.7 Applying Zig」第 72–82 段(text/10-ch01-07-1-7-applying-zig.txt:76,搜「Roc」;:79,搜「Buzz」)。原文:「The Roc language (www.roc-lang.org) relies on Zig for critical parts of its compiler.」「Embeddable scripting languages like Buzz (https://buzz-lang.dev) and Cyber (https://cyberscript.dev) are great examples.」(链接照录原书,查阅于 2026-10-19) ↩

  15. 出处:「1.7 Applying Zig」第 93–98 段(text/10-ch01-07-1-7-applying-zig.txt:94,搜「most excited」)。原文:「WebAssembly is one of the technologies I am most excited about for its potential impact in the near future.」 ↩

  16. 出处:「1.7 Applying Zig」第 100–107 段(text/10-ch01-07-1-7-applying-zig.txt:107,搜「bread and butter」)。原文:「Resource constraints, operating system integration, and speed without sacrificing reliability are its bread and butter.」 ↩

  17. 出处:「1.7 Applying Zig」第 109–113 段(text/10-ch01-07-1-7-applying-zig.txt:110,搜「overkill for GUIs」)。原文:「Zig is overkill for GUIs that don't need to be particularly optimized, and there are better solutions for fast prototyping.」 ↩

  18. 出处:「1.7 Applying Zig」第 115–123 段(text/10-ch01-07-1-7-applying-zig.txt:116,搜「In my academic work」)。 ↩

  19. 出处:「1.8 Summary」第 2–9 段(text/11-ch01-08-1-8-summary.txt:4,搜「seamless C interoperability」)。原文:「Zig offers seamless C interoperability, strict static guarantees, world-class metaprogramming, and well-designed memory semantics enabling efficient, effective development that never sacrifices simplicity.」 ↩

  20. 出处:「1.8 Summary」第 10–14 段(text/11-ch01-08-1-8-summary.txt:10,搜「killer features」)。原文:「The Zig build system is one of the language's killer features, featuring seamless handling of multi-language and cross-platform code, out-of-the-box cross-compilation, hermetic builds, custom build logic, and reproducible package management in an optimized package.」 ↩