编程语言研究书库

构建脚本与 comptime 配置 — 用编译选项把一份代码变成两个程序

构建脚本与 comptime 配置 — 用编译选项把一份代码变成两个程序

这一章讲什么: cat 已经「敢用」了,3.4 节给它上最后一道工程化: 两个用户要互相冲突的定制——一个要最小内存,一个要最大缓冲。 答案是构建脚本 + comptime:给 zig build 加两个命令行选项, 让它们以编译期常量的身份进到你的代码里, 同一份源码编译出两个不同的二进制。 这一节把第 1 章承诺的 comptime 真正兑现,顺带讲清 Zig 的四种优化档 和可选类型(optionals)。3.5 节是第 3 章的总结。

1. 这一章讲什么

戏剧情境:老朋友 Buff 和 Bill 都在 ACME 公司,cat 被安全部门下架了, 你需要给他们供一个自制版1。但要求冲突:

  • Bill 做小型 IoT 设备——刚够跑 Linux 的那种,每个 KB 都金贵2;
  • Buff 是数据分析师——要大缓冲换最大吞吐,文件以海量计3。

两人都不让步,也不讨论缓冲大小到底有多大影响。「好吧,这就是开发者的人生。 无论一个东西多完美,总有人想要『小小的』改进,理由还可能毫无道理。」4 解法:用 comptime 配置满足这两位,而这一步需要一个正经的构建脚本5。

2. 顶层全景:从 zig run 到 zig build 再到 -D 选项

  阶段 ① zig run          一次性跑代码,够用;真项目不行
  阶段 ② zig build         build.zig 定义 build graph,一键编译安装
  阶段 ③ zig build -D…     命令行选项 → options 模块 → 程序里的编译期常量
                          → 同一份代码,两个二进制(Bill 版 / Buff 版)

  图说:三级台阶,每一级把「配置」往编译期挪一格。

3. 核心原理

3.1 为什么需要构建脚本

zig run 是实验利器,但迟早要正经构建。原书给的定义: 构建脚本给 Zig 编译器提供自动化编译任务所需的全部配置—— 简单到一个可执行文件,复杂到一组互相关联、带依赖和生成文件的库与程序6。

最小骨架:构建脚本定义模块、指定编译方式,手段是造构建步骤 (build step)——通常是一个(组)要从源码或上一步输出生成的文件。 可执行文件就是「编译源码」这个步骤的产物;步骤之间互相依赖的网络 叫 build graph(构建图)7。

最关键的一句:构建脚本本身也是 Zig 程序—— 所以「你有全部代码可用,能把项目的构建系统造得和应用一样聪明」8。 对照:C 的构建是 Makefile 等一堆 DSL(专用小语言)的缝合, Chromium 那种项目还得外挂 Python 生成(见 02 篇); Zig 的构建没有第二种语言。

3.2 build.zig 的解剖

约定:代码放 src/ 目录,入口叫 src/main.zig, 构建脚本固定叫项目根目录下的 build.zig9。

入口:不写 main,写 build:

pub fn build(b: *std.Build) void {
    // build code ...
}

std.Build 这个数据结构就代表 build graph, 提供造步骤、连步骤的一排函数10。

两个标准选项(几乎人人会加):target 和 optimize。 target = 目标平台(操作系统 + CPU 的组合)——加上它, 在任何一台装了 Zig 编译器的机器上,都能为任何支持的平台交叉编译11。 optimize = 优化档,一共四档,原书表 3.112:

档特征用途
Debug编译快;兼容调试器;运行时安全检查开;不优化快速迭代、排查问题(默认档)
ReleaseFast无运行时安全检查;优化执行速度让代码跑飞
ReleaseSmall无运行时安全检查;优化二进制体积嵌入式、嵌入他处
ReleaseSafe运行时安全检查开;速度与体积只做有限优化「不出意料」优先时

注意这张表把 02 篇埋的伏笔坐实了:「安全检查开不开」是编译档位的事—— Debug/ReleaseSafe 开,ReleaseFast/ReleaseSmall 关。 所以「我的 Zig 程序会拦越界」这句话永远要带后缀:「在哪个档位」。

一个能跑的最小 build.zig(原书 listing 3.17):

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});      // ① 标准 target 选项
    const optimize = b.standardOptimizeOption(.{});   // ② 标准 optimize 选项

    const mod = b.createModule(.{                      // ③ 模块:根源文件是 src/main.zig
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    const exe = b.addExecutable(.{                     // ④ 可执行文件这个步骤
        .name = "cat",
        .root_module = mod,
    });
    b.installArtifact(exe);                            // ⑤ 挂到 install 步骤
}

zig build 默认执行的是 install step(安装步骤); b.installArtifact(exe) 就是告诉它「跑 zig build 时把这个可执行文件编出来」13。 跑完后出现两个目录:zig-out/(产物,cat 在 zig-out/bin/cat) 和 .zig-cache/(缓存的中间文件,不用管)14。 原书称这个十几行的脚本「任何 Zig 应用的地基」15—— 记住它,以后每个项目都从它长出来。

3.3 支线:可选类型(?T 与 null)

加命令行选项之前,原书插播了一个新类型,后面马上要用。

可选类型(optional) 表达「要么是某个值,要么什么都没有」: 写法 ?T(T 内部类型),「什么都没有」用 null 表示16。 Rust 玩家会认出它就是 Rust 的 Option<T>17。 还记得 08 篇的 indexOf 吗——它用错误联合表达「找不到」, 其实更贴切的表达是可选:

fn indexOf(items: []const i32, value: i32) ?usize {
    return for (items, 0..) |item, i| {
        if (item == value) break i;
    } else null;
}

配套的控制流三件,和错误联合一一对应18:

写法对可选做什么对应错误联合的
if (opt) |v| {…} else {…}有值进 if,绑给 v;null 进 elsecatch 分流
opt.?「我确定有值」,直接剥壳;错了安全模式崩(裸奔版)
opt orelse 默认值/表达式null 就用右侧顶上catch 给默认值

orelse 之于可选,正如 catch 之于错误联合——null 时执行右侧表达式19。 顺带:Zig 选 null 这个关键字不是巧合,和 C 的 NULL、C++ 的 nullptr 同源——C 集成那章会接上这条线20。

3.4 主线例子:把缓冲区大小变成编译选项

回到 Buff 和 Bill。目标:zig build 多两个选项 -Dreader-buffer-size / -Dwriter-buffer-size,默认值 1024。

第一步:选项进 build graph(原书 listing 3.20 的骨架):

pub fn build(b: *std.Build) void {
    // …target / optimize 同前…

    const reader_buffer_size = b.option(usize, "reader-buffer-size", "Reader buffer bytes")
        orelse 1024;                       // 没传 -D 就用 1024
    const writer_buffer_size = b.option(usize, "writer-buffer-size", "Writer buffer bytes")
        orelse 1024;

    const options = b.addOptions();                        // 造一个 options 容器
    options.addOption(usize, "reader_buffer_size", reader_buffer_size);
    options.addOption(usize, "writer_buffer_size", writer_buffer_size);
    const options_mod = options.createModule();            // 它是个模块!

    const mod = b.createModule(.{ .root_source_file = b.path("src/main.zig"),
                                 .target = target, .optimize = optimize });
    mod.addImport("options", options_mod);                 // 以 "options" 之名 import 它

    const exe = b.addExecutable(.{ .name = "cat", .root_module = mod });
    b.installArtifact(exe);
}

第二步:程序里用(原书 listing 3.21 的两处改动):

const options = @import("options");            // 编译器虚拟出来的模块

var stdout_buffer: [options.writer_buffer_size]u8 = undefined;
// ……
var file_buffer: [options.reader_buffer_size]u8 = undefined;

停下来看一眼这里发生了什么——这是全书的 comptime 时刻:

  命令行:zig build -Dreader-buffer-size=512 -Dwriter-buffer-size=512
      │
      ├─ b.option 收到 512(没传时是 orelse 兜底的 1024)
      ├─ addOptions 把 512 写成 options 模块里的常量
      ├─ 编译 main.zig 时,options.reader_buffer_size 就是一个已知的数
      ├─ [512]u8 —— 数组大小是类型的一部分,
      │   所以这是「变量写进了类型定义里」
      └─ 编译产物:一个缓冲区全 512 字节的 cat

  图说:同一份源码,两次编译,两个二进制。512/8192 是命令行给的真实值。

原书点破其中的不寻常:「数组的缓冲区大小是类型的一部分, 所以我们在类型定义内部引用变量!在大多数静态类型语言里, 这要好一番仪式才办得到;在 Zig 里能跑,是因为这些变量在 comptime 已知」21。 然后是一句总结性的话,值得原文引用:

「comptime 在 Zig 里无处不在、无时无刻,烘在语言核心。 它被设计得如此无缝,你——程序员——几乎可以停止区分编译期和运行期。」22

这就是 02 篇那张「comptime 顶替四样工具」表的兑现现场: 没有宏、没有模板、没有代码生成脚本—— 就是一个普通变量,从命令行流进类型,沿途每一站都是 Zig。

第三步:兑现给 Buff 和 Bill(原书的两条真实命令):

# Bill 的 IoT 版:最小体积档 + 半 KiB 小缓冲
$ zig build -Dtarget=x86_64-linux -Doptimize=ReleaseSmall \
    -Dwriter-buffer-size=512 -Dreader-buffer-size=512

# Buff 的分析版:最快速档 + 8 KiB 大缓冲
$ zig build -Dtarget=x86_64-linux -Doptimize=ReleaseFast \
    -Dwriter-buffer-size=8192 -Dreader-buffer-size=8192

两个人都得到了想要的,「我们只损失了一丁点理智」23。 注意交叉编译也顺手发生了:-Dtarget=x86_64-linux 意味着你在任何系统上 都能编出 Linux x86_64 的二进制——不需要目标机器,不需要容器。

3.5 收尾:别笑这个场景

3.4 节的最后,作者自己戳穿了这个故事的滑稽,然后补了一句认真的: 「真实开发往往也是这样的。我入行是因为享受解决问题的满足感。 但写有用的软件需要灵活和踏实(flexibility and groundedness)—— 代码可以为精确、为模式与对称、为榨干计算机而美; 但如果周围有真实的用户把一切搞砸,同样的美完全是另一场战斗。」24 这句是第 3 章的题眼:cat 的四轮改造,每一轮都是「真实用户会把一切搞砸」 的具体形态——漏内存、崩在半路、16 MiB 的文件上限、两个互相冲突的需求。

3.6 第 3 章总结(3.5 节)

原书总结六条,一句话转述:错误是一套「显式处理意外」的工具箱; 分配器要用、但要用得聪明;标准库提供跨平台的 OS 交互工具; 循环与 break/continue 给了控制流极大的表达力; 构建脚本和 comptime 能在部署之前就编码灵活逻辑; 原型与迭代是适应变化需求的办法25。

4. 作者的判断与证据

判断是书里给的证据,还是作者的推测
build.zig 是「任何 Zig 应用的地基」作者断言,骨架确实通用
「安全检查开不开」属于优化档语言事实(表 3.1 可核)
comptime「可以停止区分编译期和运行期」设计目标陈述;入门场景成立,大型元程序未必
小缓冲 vs 大缓冲的需求值得用编译选项解决教学设定;真实工程里多半直接让缓冲可运行期配置
「写有用的软件需要灵活和踏实」作者经验总结,本章四个故事是它的论据

5. 边界与局限

  • 编译期配置的代价:每换一个缓冲大小都要重编——Buff 和 Bill 拿到的是 两个静态二进制。很多真实场景需要的是运行期配置(环境变量、CLI 参数), 那条路本节完全没走,读者可能误以为 Zig 偏好编译期配置。
  • b.option 的类型安全边界:选项值在构建脚本里解析, 传错类型报错发生在「构建时」而非「编辑时」,IDE 帮不上忙。
  • 表 3.1 的四档之外没有中间档:想要「快但保留部分检查」的人只能自己拼 (或用 ReleaseSafe 再开具体优化),MEAP 未展开。
  • **optionals 的「null 与 C 的 NULL 同源」**只是埋了个钩子,C 集成本身 在后续章节,当前版本没有兑现。

6. 可带走的

  1. zig run 实验,zig build 正经;构建脚本 = 项目根目录的 build.zig, 入口 pub fn build(b: *std.Build) void;
  2. 构建脚本也是 Zig 程序——没有第二种构建语言;
  3. build graph:步骤互相依赖的网络;b.installArtifact 挂到默认的 install 步骤;
  4. 四种优化档:Debug(检查开,默认)/ ReleaseFast / ReleaseSmall / ReleaseSafe; 安全检查随档位开关;
  5. -Dtarget= 交叉编译:任何机器编任何支持的平台;
  6. b.option 加命令行选项 → addOptions 造模块 → mod.addImport → 程序里 @import("options") 拿到编译期常量;
  7. [options.reader_buffer_size]u8 是「变量写进类型」——comptime 的直接后果;
  8. optionals:?T 与 null;orelse 之于可选 = catch 之于错误联合; opt.? 是「我确定有值」的裸奔;
  9. comptime 无处不在:它不是一个功能,是语言的地心引力;
  10. 写有用软件的题眼:灵活与踏实——美在真实用户面前是另一场战斗。

7. 原文地图

主题原书章原文位置
Buff 与 Bill 的冲突需求3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:15(搜「Buff and Bill」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:20(搜「IOT devices」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:23(搜「data analyst」)
构建脚本定义与 build graph3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:47(搜「build steps」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:50(搜「build graph」)
构建脚本也是 Zig 程序3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:55(搜「just Zig programs」)
std.Build 与 install step3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:86(搜「represents the build graph」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:89(搜「installation step」)
target 与 optimize 选项3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:94(搜「TARGETS AND OPTIMIZE MODES」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:102(搜「Optimize modes tell」)
四种优化档表3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:105(搜「Table 3.1」)
zig build 产物与缓存目录3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:173(搜「zig-out」)
optionals 定义;Rust 对照3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:184(搜「OPTIONALS」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:190(搜「Rust programmer」)
orelse 之于可选 = catch 之于错误联合3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:233(搜「orelse is to optionals」)
null 与 C 的 NULL 同源3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:239(搜「isn’t a coincidence」)
b.option 与 addOptions3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:256(搜「b.option」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:267(搜「addOptions」)
「变量写进类型」与 comptime 无处不在3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:348(搜「referencing variables inside」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:350(搜「known at comptime」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:351(搜「everywhere in Zig」)
两条编译命令3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:364(搜「half kibibyte」) · text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:369(搜「8 kibibyte」)
「真实开发往往也这样」3.4 Buffering and building with Buff and Billtext/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:378(搜「real development often」)
3.5 总结3.5 Summarytext/20-ch03-05-3-5-summary.txt:9(搜「array of tools」)

Footnotes

  1. 出处:「3.4 Buffering and building with Buff and Bill」第 12–19 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:15,搜「Buff and Bill」)。原文:「You get a text from your two old friends, Buff and Bill. They both work at ACME Corp. in different roles, and they just received a company wide memo that the cat program they've been using has been removed from all systems, for security reasons.」 ↩

  2. 出处:「3.4 Buffering and building with Buff and Bill」第 20–22 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:20,搜「IOT devices」)。原文:「Bill works on small IOT devices — barely big enough to run Linux, but they do nonetheless. To him, the work requires the most minimal memory usage size possible, each kilobyte matters.」 ↩

  3. 出处:「3.4 Buffering and building with Buff and Bill」第 23–25 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:23,搜「data analyst」)。原文:「Buff is a data analyst. He absolutely demands large buffers for the maximum throughput.」 ↩

  4. 出处:「3.4 Buffering and building with Buff and Bill」第 26–31 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:29,搜「life of a developer」)。原文:「No matter how perfect something is, someone always wants 'minor' improvements or additions, and their reasons may or may not make any real sense.」 ↩

  5. 出处:「3.4 Buffering and building with Buff and Bill」第 32–34 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:32,搜「comptime configuration」)。原文:「Thankfully, we can use comptime configuration to serve these bumbling bozos and save ourselves a headache. This will require a proper build script.」 ↩

  6. 出处:「3.4 Buffering and building with Buff and Bill」第 36–45 段(3.4.1,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:47,搜「build steps」)。原文:「Build scripts provide the Zig compiler with all of the configuration necessary to automate compilation tasks.」「In their most basic form, build scripts define Zig modules and specify how they will be compiled. This is done by creating build steps, which are typically a file or set of files that must be generated from source code or the output of previous build steps.」 ↩

  7. 出处:「3.4 Buffering and building with Buff and Bill」第 47–50 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:50,搜「build graph」)。原文:「An executable is a build step that is generated by compiling source files. This network of dependent steps is known as a build graph.」 ↩

  8. 出处:「3.4 Buffering and building with Buff and Bill」第 54–58 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:55,搜「just Zig programs」)。原文:「Since they, too, are just Zig programs, you have full access to all of the code necessary to make your project's build system as intelligent as the application demands.」 ↩

  9. 出处:「3.4 Buffering and building with Buff and Bill」第 62–71 段(3.4.2,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:66,搜「folder named src」)。原文:「By convention, Zig programs are placed in a folder named src. Within that folder, the main entry point is typically placed in a file named main.zig. To use the Zig build system, our build script must be placed in a file called build.zig in the root of the project.」 ↩

  10. 出处:「3.4 Buffering and building with Buff and Bill」第 79–92 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:86,搜「represents the build graph」)。原文:「The std.Build data structure represents the build graph. It provides a number of functions for creating and hooking together build steps. For our purposes, we'll use createModule and addExecutable to create a step to build our executable.」 ↩

  11. 出处:「3.4 Buffering and building with Buff and Bill」第 94–101 段(TARGETS AND OPTIMIZE MODES 栏,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:98,搜「different environments」)。原文:「Adding these options allow you to compile your project for different environments from any computer that the Zig compiler supports.」 ↩

  12. 出处:「3.4 Buffering and building with Buff and Bill」第 102–127 段(表 3.1,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:105,搜「Table 3.1」;:102,搜「Optimize modes tell」)。原文:「Optimize modes tell the compiler the best way for a project to be compiled. There are four of them tailored to different situations.」 ↩

  13. 出处:「3.4 Buffering and building with Buff and Bill」第 89–92 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:89,搜「installation step」)。原文:「Build scripts automatically start with a step called the installation step (or just install step), which is the step that is built when the command zig build is run on the command line.」 ↩

  14. 出处:「3.4 Buffering and building with Buff and Bill」第 170–176 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:173,搜「zig-out」)。原文:「Two new directories will appear, named zig-out and .zig-cache. The former contains compiled output, and the latter is full of cached intermediate files.」「The cat program we just compiled will appear in zig-out/bin/cat.」 ↩

  15. 出处:「3.4 Buffering and building with Buff and Bill」第 163–168 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:163,搜「basis for any Zig application」)。原文:「This little build.zig is the basis for any Zig application.」(含 TIP:「This build script is the basis」) ↩

  16. 出处:「3.4 Buffering and building with Buff and Bill」第 184–188 段(OPTIONALS 栏,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:184,搜「OPTIONALS」;:187,搜「?T」)。原文:「Optionals are a semantically and syntactically rich way to encode values that could be either something or nothing. Zig uses the syntax ?T to write an optional value, where T is the inner type. The value null is used to represent an optional with nothing in it.」 ↩

  17. 出处:「3.4 Buffering and building with Buff and Bill」第 190 段(TIP,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:190,搜「Rust programmer」)。 ↩

  18. 出处:「3.4 Buffering and building with Buff and Bill」第 208–229 段(listing 3.19,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:230,搜「unwrap」;:225,搜「orelse」)。三种写法(if 解包、.?、orelse)逐条照 listing 3.19。 ↩

  19. 出处:「3.4 Buffering and building with Buff and Bill」第 233 段(listing 3.19 的 #3 注释,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:233,搜「orelse is to optionals」)。原文:「orelse is to optionals as catch is to error unions. If the optional is null, its expression will be executed.」 ↩

  20. 出处:「3.4 Buffering and building with Buff and Bill」第 238–240 段(注记,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:239,搜「isn’t a coincidence」)。原文:「An astute reader may have noticed that Zig's choice of the null keyword sounds a lot like C's NULL or C++'s nullptr. This isn't a coincidence! We'll see how they're connected when we start integrating C code.」 ↩

  21. 出处:「3.4 Buffering and building with Buff and Bill」第 346–350 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:348,搜「referencing variables inside」;:350,搜「known at comptime」)。原文:「The buffer size for an array is part of the type, so we're referencing variables inside of the type definition! In most statically typed languages, this would require a lot more ceremony to achieve. In Zig, this kind of code works because the variables are known at comptime.」 ↩

  22. 出处:「3.4 Buffering and building with Buff and Bill」第 351–354 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:351,搜「everywhere in Zig」)。原文:「Comptime is everywhere in Zig at all times, baked into the core of the language. It is designed to fit so seamlessly into the code that you, the programmer, can almost stop thinking about the compile-time vs. runtime distinction.」 ↩

  23. 出处:「3.4 Buffering and building with Buff and Bill」第 357–375 段(text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:364,搜「half kibibyte」;:369,搜「8 kibibyte」;:374,搜「lost only a minimal」)。两条 zig build 命令照原文,512 与 8192 字节为命令行真实值。 ↩

  24. 出处:「3.4 Buffering and building with Buff and Bill」第 377–382 段(3.4.4 与「3.5 Summary」开头,text/19-ch03-04-3-4-buffering-and-building-with-buff-and-bill.txt:378,搜「real development often」;text/20-ch03-05-3-5-summary.txt:2,搜「groundedness」)。原文:「Maybe this scenario seems silly — because, frankly, real development often is, too.」「What I soon learned was that writing useful software requires flexibility and groundedness.」「The real challenge lies in building similar beauty with real users around to screw everything up.」 ↩

  25. 出处:「3.5 Summary」第 8–20 段(text/20-ch03-05-3-5-summary.txt:9,搜「array of tools」)。六条总结逐条对应原文:「Errors contain an array of tools to explicitly handle unexpected circumstances.」「Use allocators to dynamically allocate memory, but use them wisely.」「The standard library provides friendly and cross-platform tools to interact with the operating system.」「For loops, while loops, break, and continue provide a ton of flexibility to express control flow.」「Build scripts and comptime are able to encode flexible logic and streamline development before you actually deploy your project.」「Use prototyping and iteration to explore problems and adapt to changing requirements.」 ↩

On this page