程序解剖 — 模块、类型、函数,和控制流也是表达式
程序解剖 — 模块、类型、函数,和控制流也是表达式
这一章讲什么: 第 2 章第 1 节做解剖:一个四行的小程序,拆出模块、 内建函数、变量、类型、函数、控制流、访问控制七个器官,并且每个器官都 回答同一个问题——「这件事在别的语言里是谁悄悄做的?在 Zig 里它明写在哪?」 读完你会理解 Zig 程序的全部骨架,以及一句很狂的话:「文件就是结构体」。
1. 这一章讲什么
2.1 节从 listing 2.1 出发:
const std = @import("std"); // #1
pub fn main() void { // #2
const x: i32 = 42; // #3
std.debug.print("{}\n", .{x}); // #4
}四行,但作者绕着它讲了一整节:@import 是什么、std 从哪来、
i32 为什么需要手写、函数怎么定义、整数溢出会发生什么、
if 为什么不只是语句、把函数拆到另一个文件要动哪里,
最后还有一个反转——main 不是你程序的第一个函数,标准库的 start 代码才是。
2. 顶层全景:四个器官一张图
源文件(在 Zig 眼里就是一个 struct 类型)
│
├─ ① 内建函数(@import):编译器直接提供,@ 开头
│ └─ 拉来模块(std 或别的 .zig 文件)
│
├─ ② 声明:const / var / fn,带不带 pub 决定外部能不能见
│
├─ ③ main:只是「一个 pub 的无参函数」,
│ 真正先跑的是 std 的 start 代码,它再调你
│
└─ ④ 运行时规则:代码必须住在函数里;
从 main 出发,一程一程往下调
图说:这就是 2.1 节的全部器官。剩下的是它们的咬合细节。3. 核心原理
3.1 模块与内建函数:@import 的两个身份
先解释两个词。
模块(module):Zig 组织代码的方式。每个模块由一个根源文件定义, 加上它直接或间接 import 的所有文件——根 import 的、被 import 的再 import 的, 全部算在内。无论你是写可执行程序、系统库还是一个顺手的小接口, Zig 都把你看成一个模块1。
内建函数(builtin):编译器直接提供的函数,所有 Zig 代码里都能用,
干的是普通 Zig 代码干不了的底层活;认法很简单——@ 开头,比如 @import2。
@import("std") 干的事:把标准库这个模块拉进来,赋给一个 const(std),
之后用点语法一层层进去:std.debug.print 是 std 里面的 debug 里面的 print3。
注意 import 的结果是一个类型(后面会说,源文件定义的就是 struct 类型),
所以你才能用点语法访问它里面的声明。
运行时的一条硬规则:代码必须住在函数里。 程序跑起来时, 每个被调用的函数不是被 main 直接调用,就是被 main 调用的函数调用—— 「我想你明白我的意思」是原书的原话4。 相对的,编译期(comptime,编译器编译你代码时执行的那段过程)执行的代码 不受这条限制——运行期与编译期的区别这本书会反复回来讲5。
3.2 变量与类型:const/var 之外,宽度是显式选择
声明的零件。 一个 Zig 变量声明由固定的几件构成:const 或 var、名字、
(可选的)类型标注、=、初值。
const 与 var 的唯一区别:var 允许之后重新赋值;const 不行。 编译器会尽力强迫你用 const——没被改过的东西不该是 var6。
类型标注什么时候可以省。 多数时候从上下文看得清类型,就不必写。
listing 2.1 里 42 必须写成 i32,是因为很多类型都能装下 42
(u8、i64、u32……),编译器需要你替它做决定7。
相反,true/false 无歧义,直接推断成 bool8。
静态 + 强类型,两个词当场解释。 原书给了一对定义,值得接住:
- 静态类型:编译器必须在分析代码时推断出每个变量、每个表达式的类型, 推断不出就报错请你帮忙;Zig 的语法本身就是为减少歧义设计的9;
- 强类型:不允许任何含糊的类型转换。想把 bool 当整数、把 int 转成 float, 必须显式声明——通常用内建函数9。
基本类型表(原书表 2.1,挑你会天天见的):
| 名字 | 是什么 | 备注 |
|---|---|---|
bool | 真/假 | |
i32、i64、i17… | 有符号整数(i + 位数),二进制补码 | 位数可以任意:0 到 65535 位都行;实践中多用 i32/i6410 |
u8、u32、u64… | 无符号整数 | 实践中常用 u8(字节) |
usize / isize | 专为下标、偏移设计的整数 | 位数 = 指针的位数(64 位机器上就是 64 位) |
f16…f128 | 浮点 | |
void | 「什么都没有」的类型,只有一个可能的值 | 类似 C 的 void 返回类型,和 C 的 void* 毫无关系 |
type | 类型本身也是值! | type 的类型还是 type——这是 comptime 元编程的后果,后文反复用11 |
注意表里藏着的两个 Zig 式选择:整数宽度任意(i17、u23 都是合法类型),
和 usize 与指针同宽。它们都是「让类型精确描述数据」这条原则的推论。
3.3 函数:主线例子 fibonacci,从 f(4) 走到溢出
这一章的主线例子是递归斐波那契。原书用它一次讲清函数定义、 return、类型推断、运算符、整数溢出五件事——我们也用它:
fn fibonacci(n: usize) i32 {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
pub fn main() void {
const first = fibonacci(1);
const second = fibonacci(2);
const third = fibonacci(3);
const fourth = fibonacci(4);
std.debug.print("{} {} {} {}\n", .{ first, second, third, fourth });
}一个零件一个零件看。 n: usize 是参数——作者特意选 usize,
因为它常用来表示「索引」,强调 n 是个序号;返回类型 i32 是够用的通用整数。
零件背后的规则:函数参数永远是 const——进函数的参数不许重新赋值12。
return 的纪律。 除非函数返回 void,return 必须带一个值,且类型要匹配返回类型;
编译器也会拿返回值来推断——这里 base case 的 0 和 1 就被推断成 i32。
忘了 return?编译器报错拒绝编译13。main 里四个变量全都没写类型标注:
Zig 会用函数返回类型推断它们14。
主线例子走一遍:fibonacci(4) 的完整调用树。 每一步旁边是具体的数:
fibonacci(4)
├─ fibonacci(3)
│ ├─ fibonacci(2)
│ │ ├─ fibonacci(1) → 1
│ │ └─ fibonacci(0) → 0
│ │ 1 + 0 = 1
│ └─ fibonacci(1) → 1
│ 1 + 1 = 2
└─ fibonacci(2)
├─ fibonacci(1) → 1
└─ fibonacci(0) → 0
1 + 0 = 1
2 + 1 = 3
输出:1 1 2 3(即 f(1) f(2) f(3) f(4))
图说:这就是程序运行时真实发生的全部调用。数字是程序算出来的,不是编的。运算符与溢出:同一个例子的暗线。 这个「直觉但低效」的递归不是白选的—— 原书借它埋了一个 Guess and Check(猜一猜,试一试):把 n 调大到 47, 会发生什么?15
答案是:程序 panic(崩溃),栈回溯指向——加法?! 因为 Zig 的 +
在安全模式下检查整数溢出;无意间的溢出在 Zig 里是非法行为
(illegal behavior),而 C/C++ 里同样的行为叫「未定义行为」,后果未知16。
这正是 02 篇说的「危险但显式」的第一处实例:如果溢出是你有意要的,
用回绕加法 +%(减法对应 -%),它按二进制补码的规则直接绕回去17;
想防溢出,标准库 std.math 里有一组函数。
| 写法 | 溢出时 | 什么时候用 |
|---|---|---|
a + b | 安全模式崩溃;ReleaseFast 不查 | 默认——你不认为会溢出 |
a +% b | 绕回(模 2^位数) | 哈希、计时器回绕等你要回绕的地方 |
std.math.add(a, b) | 溢出时返回错误 | 数据来自外部,必须优雅处理 |
3.3.1 运算符速览:熟悉的面孔,更严的纪律
fibonacci 里已经见过 + 和 ==,原书借表 2.2 把常用的运算符一次摆全18:
| 运算符 | 干什么 | 和 C 的差别 |
|---|---|---|
+ - * | 加减乘 | 断言不溢出——和上面那条暗线一致 |
/ | 除法 | 只除浮点;整数除它不管 |
@divFloor | 整除并向下取整 | 整数相除用这个 |
@divExact | 整除,且断言没有余数 | 能整除才有结果,否则安全模式崩 |
> < >= <= | 比大小 | 一样 |
== != | 相等、不等 | 一样 |
这张表里最「Zig」的一格是 /:C 里 7 / 2 默默给你 3(整数除法),
Zig 里 7 / 2 直接编译错误——两个整数不能用 /,
你必须说清要哪种除法:向下取整(@divFloor(7, 2) 得 3)、
还是精确整除(@divExact,除不尽就崩)。
这又是同一个公式:别的语言替你猜的地方,Zig 要你显式选。
@ 开头的这几个是内建函数,不是运算符——所以它们能带参数、能各有各的断言。
原书对整组运算符的评价也值得接住:它们和 C 系语言高度对应, 并不古怪;偶尔哪个的用法和别家不一样,编译器会把你往对的方向引19。 「编译器当教练」在这里有了具体样子:不是报错甩锅,而是指路。
3.4 控制流也是表达式:没有 truthiness,else if 是幻觉
Zig 的 if/else 长得像 C:条件外面必须带括号。但有两处根本不同。
第一,没有「真值」概念。 条件必须是 bool——if (1) 这种在 C 里成立
(非零即真)的写法,在 Zig 里直接编译错误:「Zig 里没有 truthiness 这个概念」20。
这是「类型转换不许含糊」在控制流上的投影。
第二,控制流是表达式。 if/else 本身有值:
const x: i32 = if (a > 3) 42 else 24;原书特别点出:语法图里根本没有 else if——所谓的 else if,
实际上是「第一个 if 的 else 分支里嵌了第二个 if 表达式」21。
而且这是普遍规律:「Zig 里所有控制流结构都是表达式」22。
(第 08 篇会看到 for 循环也返回值。)书里还补了一句:这让 C 家族那个
饱受争议的「三元运算符 ?:」没了存在的必要23。
3.5 模块、pub,和「main 到底是谁调的」
回到模块。把 fibonacci 挪进单独文件 fibonacci.zig,
main 文件里 const fibonacci = @import("fibonacci.zig").fibonacci;——
@import 吃任何相对路径,返回的类型的声明直接取24。
改动只有一处:函数前面加 pub。
pub 是 Zig 访问控制的全部:它告诉编译器「别的源文件 import 这份代码后允许访问」。
同一文件内的代码不受限——同文件的所有代码都能访问文件里的一切25。
没有 protected、private、package 这些层级,一个关键字封顶。
反转:main 也是被别人调用的。 拆到这里,原书问了一个读者此刻
该问的问题:「等等,你是说有 Zig 代码在调 main?」验证方法简单到可爱:
把 pub fn main 的 pub 删掉再跑——你会得到一条错误,
lib/std/start.zig:614:46: error: 'main' is not marked 'pub'root 是 Zig 启动代码给你那个源文件起的名字;它在标准库的 start.zig 里
找你的 main,发现它不是 pub,够不着,于是报错26。
作者的感慨:「真的是一路 Zig 通到底(It really is Zig all the way down)」27——
你的程序的入口、运行时的初始化,全是你也能读、也能改的 Zig 代码,
不是编译器里黑箱的魔术。
为什么敢这么说:文件就是 struct。 2.1 节埋的最重要的伏笔在这一句: 源文件在 Zig 里定义的就是一个 struct 类型;甚至「编译器解析源文件和 解析结构体用的是同一份代码」28。这句话第 06 篇会兑现—— struct 里可以放声明、可以当命名空间用,文件也是; 理解了 struct 就理解了模块,反之亦然。
三个词的官方定义(原书表 2.3)。 这一节收尾处,作者按 Zig 的口径 把三个容易混的词钉死29:源文件,是装着 Zig 代码的文件, 里面带 pub 声明供别人 import;模块,从根源文件出发、 把它递归涵盖的所有源文件算在一起的整体;命名空间,则是 「任何能装声明的类型」——源文件是,struct 也是。 记住第三个定义最宽的:它解释了为什么 import 一个文件得到的类型 能用点语法一层层访问,也预告了 struct 的双重身份。
3.6 收尾:就靠这点东西?
2.1 节的最后一句是给怀疑者的:「方法集小到让人怀疑怎么干正事—— Zig 可扩展性的关键在于可组合性(composability):一小撮简单想法, 零件可互换。工具越少,挑工具的时间越少;零件之间的语义被打磨得越精, 它们拼起来的行为越好预测」30。 这是第 02 篇「极简语言」主题的工程版回答:不是靠特性多,是靠零件咬合得准。
4. 作者的判断与证据
| 判断 | 是书里给的证据,还是作者的推测 |
|---|---|
| 静态+强类型能减少歧义类 bug | 设计立场,与 1.3 节「歧义就是技术债」一脉相承,无对照数据 |
+ 检查溢出、「无意溢出是非法行为」 | 语言规范事实,可验证 |
| 所有控制流都是表达式 | 语言事实,例子可跑 |
| 没有 else if 是「Zig 精简语法」的一例 | 作者解读(它仍是普遍可用的语法糖) |
| 可组合性是 Zig 可扩展性的关键 | 作者的设计哲学断言 |
5. 边界与局限
- 整数「任意位数」有实务脚注:位数上限 65535; 而且 i17、u23 这类非标准宽度运算会慢一点—— 数据摆放对不齐机器喜欢的位置时要多花指令,书提了前者,没提后者。
- 「函数参数永远是 const」有一个读者迟早撞见的推论:想改传进来的东西,
得传指针(
*T)。这是第 05 篇的主角之一。 - 递归的 fibonacci 被反复提醒「不是高性能代码」, 但更快的写法(改成循环、或把算过的结果存起来重复利用)书里没给—— 性能话题整个 MEAP 都着墨不多。
- 表 2.1 之外还有不少类型(comptime 专用的、
noreturn、可选类型?T), 本节只露了一角,后面章节陆续给。
6. 可带走的
- 模块 = 根源文件 + 递归 import;
@import吃模块名也吃相对路径,返回类型; - 内建函数 = 编译器提供、
@开头、干普通代码干不了的底层活; - const/var 的唯一区别是「能不能重新赋值」;参数永远是 const;
- 整数宽度是显式选择(42 必须说清是 i32),位数可以任意;
usize与指针同宽,专管下标和长度;- 类型推断覆盖「初值无歧义」和「函数返回值」两种情形;
+安全模式查溢出;要回绕写+%,要防溢出用std.math;- 条件必须 bool,没有 truthiness;所有控制流都是表达式,else if 是嵌套幻觉;
- 访问控制只有一个
pub,同文件内不设防; - main 是标准库 start 代码调的;把
pub删掉,报错会亲自告诉你这件事。
7. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 模块的定义 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:47(搜「Modules are units」) |
| 内建函数的定义 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:41(搜「Builtin functions are provided」) |
| 点语法与 std.debug.print | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:52(搜「dot」) |
| 代码必须住在函数里 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:57(搜「as opposed to compile time」) |
| const/var 与编译器强迫 const | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:79(搜「either const or var」) |
| 类型标注:i32 与 42 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:88(搜「could represent 42」) |
| 静态 + 强类型定义 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:91(搜「statically and strongly typed」) |
| 基本类型表 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:133(搜「two’s-complement」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:163(搜「type is a consequence」) |
| bool 推断 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:117(搜「unambiguously boolean」) |
| fibonacci 函数与参数 const | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:183(搜「one parameter named n」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:186(搜「always const」) |
| return 必须有值且匹配 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:227(搜「matches the return type」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:230(搜「refuse to compile」) |
| 用返回类型推断变量 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:238(搜「OMITTING TYPE ANNOTATIONS」) |
| 溢出、panic 指向加法、+% | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:287(搜「stack trace」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:292(搜「wrapping addition」) |
| 没有 truthiness | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:309(搜「truthiness」) |
| else if 是嵌套幻觉;控制流皆表达式 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:312(搜「there is no else if」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:316(搜「all control flow」) |
| 三元运算符退场 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:323(搜「ternary」) |
| pub 是访问控制的全部 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:374(搜「addition of the pub keyword」) · text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:377(搜「same file has access」) |
| 文件定义 struct 类型 | 2.1 The anatomy of a Zig program | text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:390(搜「struct type in Zig」) |
| 删 pub 的报错;start.zig;一路 Zig 通到底 | 2.1 The anatomy of a Zig program | text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:9(搜「not marked 'pub'」) · text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:21(搜「Zig all the way down」) |
| 可组合性是扩展性的关键 | 2.1 The anatomy of a Zig program | text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:28(搜「composability」) |
Footnotes
-
出处:「2.1 The anatomy of a Zig program」第 46–50 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:47,搜「Modules are units」)。原文:「Modules are units of Zig code. Every module is defined by a root source file, and all files it imports recursively.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 39–44 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:41,搜「Builtin functions are provided」)。原文:「Builtin functions are provided by the compiler and are available in all Zig code. They cover a variety of low-level tasks that can't be implemented in ordinary Zig code. You can easily identify a builtin by the @ prefix (like @import).」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 51–55 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:52,搜「dot」)。原文:「Zig uses the familiar dot (.) syntax to reference functions, variables, and other namespaces within a namespace.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 56–60 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:57,搜「as opposed to compile time」)。原文:「Zig code that executes at runtime (as opposed to compile time or comptime) must live within a function. Every runtime function called in a Zig program is called from either the main function or a function called by main — or a function that was called by a function called by main. I think you get the point.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 63–67 段(注记)。「The distinction between runtime and compile time is especially important in Zig… Compile time, or in Zig parlance, comptime, refers to code that the Zig compiler executes while your code is being compiled into machine executable form.」 ↩
-
出处:「2.1 The anatomy of a Zig program」第 79–83 段(图 2.1 的图注,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:79,搜「either const or var」)。原文:「The only distinction between the two is that a variable declared var is allowed be reassigned. The Zig compiler tries to enforce const as much as possible. If something isn't reassigned or modified, there is no need for it to be a var — and the compiler will complain.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 86–90 段(图 2.1 的图注,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:88,搜「could represent 42」)。原文:「Type annotations are not always necessary in Zig… In this case, many types could represent 42 at runtime, so we need to give it a type. i32 is a signed 32-bit integer type, perfectly adequate for our purposes here.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 108–118 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:117,搜「unambiguously boolean」)。原文:「Zig allows the type annotation to be omitted because true and false are unambiguously boolean values.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 91–102 段(图 2.1 的图注,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:91,搜「statically and strongly typed」;:93,搜「deduce the type of every variable」)。 ↩ ↩2 -
出处:「2.1 The anatomy of a Zig program」第 133–142 段(表 2.1,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:133,搜「two’s-complement」;:136,搜「from 0 to 65535」)。 ↩ -
出处:「2.1 The anatomy of a Zig program」第 159–165 段(表 2.1 的 type 行,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:163,搜「type is a consequence」)。原文:「Types in Zig are actually values, too! The type of a type is type.」「type is a consequence of Zig's comptime metaprogramming.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 183–187 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:183,搜「one parameter named n」;:186,搜「always const」)。原文:「Fibonacci is a function with one parameter named n, with the type usize.」「Function parameters in Zig are always const.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 225–231 段(RETURN 栏,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:227,搜「matches the return type」;:230,搜「refuse to compile」)。原文:「return statements must include a value that matches the return type of the function.」「If you forget to return a value, the compiler will complain and refuse to compile your code.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 239–244 段(OMITTING TYPE ANNOTATIONS 栏,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:238,搜「OMITTING TYPE ANNOTATIONS」)。原文:「Zig also uses the return type of a function to infer the type of any variable initialized with the result of a function.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 279–285 段(GUESS AND CHECK,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:282,搜「n = 47」)。 ↩ -
出处:「2.1 The anatomy of a Zig program」第 286–291 段(GUESS AND CHECK 的解答,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:287,搜「stack trace」)。原文:「a runtime panic is triggered and the program will display a stack trace that leads to… addition?! Zig's + operator actually checks for integer overflow (in safe mode). Invoking integer overflow without intention is considered illegal behavior in Zig. In C and C++, signed integer overflow is instead considered undefined behavior with unknown consequences.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 291–296 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:292,搜「wrapping addition」)。原文:「One alternative… would be to use the wrapping addition operator, written as +%, which will simply ignore the overflow and wrap around as you might expect from a two's complement number.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 251–276 段(表 2.2,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:256,搜「Table 2.2」;:262,搜「asserting that numbers will not overflow」;:264,搜「Divide floating point values」;:266,搜「@divFloor」;:269,搜「@divExact」)。表内各格照原书。 ↩ -
出处:「2.1 The anatomy of a Zig program」第 297–299 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:298,搜「Operators closely match」)。原文:「Operators closely match up to other C-like languages. If you happen to use an operator Zig does a little differently, the compiler tries to steer you in the right direction.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 305–310 段(图 2.3 的图注,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:309,搜「truthiness」)。原文:「There is no concept of truthiness in Zig, the condition must be a bool.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 312–315 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:312,搜「there is no else if」)。原文:「You may notice that there is no else if construction in this syntax diagram… the else if is actually a second if expression inside the else expression of the first if expression.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 316–318 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:316,搜「all control flow」)。原文:「In fact, all control flow constructions in Zig are expressions. They can return values just like most expressions.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 323–325 段(TIP,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:323,搜「ternary」)。原文:「Control flow expressions remove the need for the controversial ternary syntax that exists in C and many C-like languages.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 334–370 段(listing 2.5/2.6 及其讲解,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:385,搜「any relative path」)。原文:「@import will happily handle any relative path you give it, assuming that it's a path to a file containing Zig code.」「@import is actually an expression, too! It returns a type that contains declarations, which can be referred to as a namespace.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 372–381 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:374,搜「addition of the pub keyword」;:377,搜「same file has access」)。原文:「pub tells the Zig compiler that other source files that import this code are allowed to access a function or global variable. This is as far as the idea of access control goes in Zig. Any code written in the same file has access to all code throughout the file.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 1–22 段(listing 之后的实验,
text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:9,搜「not marked 'pub'」)。原文:「lib/std/start.zig:614:46: error: 'main' is not marked 'pub'」;「root is the name the Zig start code assigns your imported source file to.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 21–22 段(
text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:21,搜「Zig all the way down」)。原文:「It really is Zig all the way down.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 388–391 段(
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:390,搜「struct type in Zig」)。原文:「Source files define a struct type in Zig, which will become more meaningful later in the chapter.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 396–415 段(表 2.3,
text/12-ch02-01-2-1-the-anatomy-of-a-zig-program.txt:398,搜「Table 2.3」;:412,搜「Any type in Zig that could contain」)。三个定义照原书:「Source File: A file containing Zig code, which contains pub declarations for other source files and modules to import and use.」「Module: A set of source files, that starts with a root source file, and includes every source file imported by root or any other source file in the module.」「Namespace: Any type in Zig that could contain declarations.」 ↩ -
出处:「2.1 The anatomy of a Zig program」第 24–31 段(2.1.5,
text/13-ch02-02-2-2-pointing-you-in-the-right-direction.txt:28,搜「composability」)。原文:「The key to Zig's scalability is in its composability. Zig is built around a small set of simple ideas with interchangeable parts. A smaller set of tools means less time spent deliberating which tool is right for the job, and well-refined semantics around how they interact with each other.」 ↩