跳转至

变量与数据类型——大体真实的一章里掺的三粒沙子

这一章讲一件事: 原书第三章教你怎么声明变量、有哪些基本类型、 什么时候写类型标注、字面量怎么写。这一章九成是真的——这正是它值得细看的原因: 你能清楚看到这本书「词条层抄对了、机制层全靠借」的分界线画在哪里。

1. 这一章讲什么

原书第三章四节:3.1 声明变量(var、作用域、常量),3.2 数据类型(整数、浮点、布尔、 字符、字符串),3.3 类型推断与类型标注,3.4 常量与字面量(含原始字符串)1。 四节的骨架是标准入门课的骨架,每个例子都能读。 我们的拆解照它的顺序走, 每到一处标「真 / 假 / 半真」。

2. 顶层全景:一张类型表的旅行

拿 3.2 节那张整数类型表当主线例子,从头走到尾——这张表是全书第一个 「可以放心抄进自己笔记」的东西:

  书中的类型        位宽   取值范围(书给的上界)      核对
  ─────────────────────────────────────────────────────────
  u8               8    0 ~ 255                    真(官方一致)
  u16              16   0 ~ 65535                  真
  u32              32   0 ~ 4294967295             真
  u64              64   0 ~ 18446744073709551615   真
  i8               8    -128 ~ 127                 真
  i16              16   -32768 ~ 32767             真
  i32              32   -2147483648 ~ 2147483647   真
  i64              64   ±9223372036854775807 量级   真

  图说:一张 8 行表 8 行全真。命名规则 u=无符号( nonnegative)、i=有符号,
  后面跟位宽——这个规则在 C/Rust/Zig 里是同一套,书抄对了。

顺便给一个真实的参照物,帮助你记住这些位宽意味着什么:u8 的 255 刚好装下一字节, 也是颜色的单通道值(红绿蓝各占一个 u8);u32 的 42 亿接近地球人口数的 5 倍, 够给每个人发一个不重复的编号;i64 的取值范围接近「以纳秒计数的 292 年」, 所以时间戳常用它。这三个锚点不是书里的,是通用知识,但能让你对这些上界有量感。

命名规则顺带说清:行话叫「位宽」(bit width),指这个类型用多少个二进制位存一个数。 u8/i8 是 8 位 = 1 字节,以此类推。

3. 核心原理之一:var 与 const——真的,且是 Zig 的门面

书教的两条规则真实成立:

  • var x: i32 = 42; 声明一个可变变量,类型写在冒号后;
  • const PI = 3.14159; 声明一个不可变常量,之后不能改2。

这和真实 Zig 一致,而且 const 优先正是 Zig 社区的真实风格(能 const 就不 var)。 类型推断(不给类型、让编译器按初值猜:var y = 3.14; 猜成 f64)也是真的2。

这里要解释一个全书反复出现、但书自己从没解释过的词:

类型推断(type inference)指你不写明类型、编译器根据初始值推出来的能力。 比如 3.14 默认是 f64(双精度浮点),42 默认按 i32(32 位整数)处理。 真实 Zig 里推断的规则和书讲的基本一致,所以书这一节可以放心用。

作用域(scope)指一个变量在代码里「能被看见」的范围:在函数或代码块里声明的 是局部变量,出来就看不见;函数外面声明的是全局的2。这条也是真的。

4. 核心原理之二:第一粒沙子——一行声明多个变量

书里写了一种「省行」的声明写法:

var a, b, c: i32;

真实 Zig 不接受这行代码。 Zig 里每个变量要单独声明(var a: i32 = 0; var b: i32 = 0;), 没有这种「逗号分隔、共享一个类型标注」的语法——那是 JavaScript 的写法。 这一粒沙子小,但有标志性:它不在任何别的「语言特征缝合」名单里, 纯粹是书作者(或生成者)的语法直觉漏进来了。

5. 核心原理之三:第二粒沙子——[T] 泛型预览

3.3 节末尾,书突然给了一个「泛型函数」的预告例子:

fn swap[T](a: T, b: T) (T, T) {
    return (b, a);
}

这个写法不是 Zig。方括号类型参数 [T] 是 C#、Java、Kotlin 一路的语法; 真实 Zig 的泛型是另一个完全不同的思路(「类型是编译期值,泛型就是一个 返回 type 的普通函数」),我们留到第 11 章展开,官方文档的示例长得像这样:

fn List(comptime T: type) type {
    return struct { items: []T, len: usize };
}

为什么这粒沙子重要: 它出现在「类型标注」这一节里最不起眼的位置, 像是作者(或生成器)从别的语言素材里顺手带进来的。它预告了第 14 章 整章的虚构泛型——那里书会把 [T]、where、trait 一次用齐。

6. 核心原理之四:第三粒沙子——r#"..."# 原始字符串

3.4 节教「原始字符串字面量」,说 Zig 用 r# 和 # 包住字符串, 这样里面的 " 和 \ 不用转义,例子是 Windows 路径3。

核对:r#"..."# 是 Rust 的语法,不是 Zig 的。真实 Zig 处理多行文本用 每行以 \\ 开头的多行字符串写法,转义规则也和书说的不一样。 书连例子的内容(Windows 路径)都透着 Rust 教材的味道。

这一粒沙子给了全书一个可复用的判别模板: 当一个语法「能绕过转义、 长得很贴心」时,先查它是哪门语言发明的,再信它是 Zig 的。

7. 作者的判断与证据

  • 经核对可用的内容: 整张整数/浮点类型表、var/const 语义、类型推断、 作用域、常规字面量(整数 0x1234、浮点 1.2e3、布尔、普通字符串)12。
  • 经核对不可用的内容: var a, b, c: i32; 多变量声明、fn swap[T] 泛型预览、 r#"..."# 原始字符串3。
  • 一个值得注意的缺席: 真实 Zig 类型系统里最有特色的三样东西—— 可选类型(?T,用 ? 表示「可能没有」)、错误联合(!T)、 comptime_int(编译期整数,42 真正的默认类型)——书一个字没提。 不是漏了,是这些机制没有可借的现成模板。

8. 边界与局限

  • 书把字符类型说成 u8、字符串说成 []const u8(一段只读的 u8 切片)—— 这个口径大体可用,但真实 Zig 里没有独立的「字符类型」, 'A' 这样的字符字面量是个编译期整数,可以隐式变成 u8。
  • 书没讲整数溢出会发生什么。真实 Zig 在安全构建模式下溢出会当场 panic (程序崩溃并报错),在 ReleaseFast 下则是「未定义行为」—— 这是 Zig 安全模型的一根支柱,比「取值范围表」更值得入门者先知道。
  • 选类型那一节(「需要大整数就用 64 位」)的直觉通用,但真实 Zig 还有 usize(数组下标用的无符号类型)这个天天要用的类型,书没有列。

9. 可带走的

  1. 这张类型表可以抄:u8~u64、i8~i64 的位宽和取值范围是全书第一批全真词条。
  2. var 可变、const 不可变、const 优先——真 Zig 同口径,照做。
  3. 三粒沙子记住两个就够:var a, b, c: i32; 和 r#"..."# 都不是 Zig——一个是 JS 直觉,一个是 Rust 语法。
  4. fn swap[T] 这种方括号泛型是 C#/Java 的;Zig 的泛型完全是另一个思路(第 11 章)。
  5. 类型推断的规则(3.14 是 f64、42 是 i32 口径)可用,但真实 Zig 里字面量的默认类型其实是 comptime_int,灵活得多。
  6. 真实 Zig 类型系统的三样招牌——可选类型 ?T、错误联合 !T、溢出即 panic——书全没讲,别在这里找。

10. 原文地图

主题 原书章 原文位置
var/const 声明、类型推断、作用域 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:7(搜「Variables are used to store values」) · text/06-ch03-chapter-3-variables-and-data-types.txt:19(搜「Type Inference」) · text/06-ch03-chapter-3-variables-and-data-types.txt:33(搜「Variable Scope」)
整数类型表 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:69(搜「Unsigned 8-bit integer」)
浮点、布尔、字符、字符串 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:87(搜「decimal point」) · text/06-ch03-chapter-3-variables-and-data-types.txt:105(搜「represented as u8 values」) · text/06-ch03-chapter-3-variables-and-data-types.txt:113(搜「slices of u8」)
多变量声明的沙子 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:27(搜「multiple variables of the same type」)
[T] 泛型预览 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:171(搜「generic functions」) · text/06-ch03-chapter-3-variables-and-data-types.txt:177(搜「fn swap[T]」)
字面量与 r# 原始字符串 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:205(搜「Integer literals」) · text/06-ch03-chapter-3-variables-and-data-types.txt:231(搜「enclosed in r# and #」)
何时用推断、何时用标注 Chapter 3: Variables and Data Types text/06-ch03-chapter-3-variables-and-data-types.txt:151(搜「Use type inference when the type is obvious」)

  1. 出处:「Chapter 3: Variables and Data Types」第 5、63、125、185 段(text/06-ch03-chapter-3-variables-and-data-types.txt:5,搜「3.1 Declaring Variables」;:63,搜「3.2 Data Types」;:125,搜「3.3 Type Inference」;:185,搜「3.4 Constants and Literals」)。 ↩↩

  2. 出处:「Chapter 3: Variables and Data Types」第 7–61 段(text/06-ch03-chapter-3-variables-and-data-types.txt:13,搜「var x: i32 = 42」;:19,搜「Type Inference」;:23,搜「inferred to be f64」;:35,搜「Variables have a scope」;:55,搜「const keyword」)。var/const 语义与类型推断均与真实 Zig 一致。 ↩↩↩↩

  3. 出处:「Chapter 3: Variables and Data Types」第 27–31 段(text/06-ch03-chapter-3-variables-and-data-types.txt:27,搜「multiple variables of the same type」;:31,搜「var a, b, c: i32」)、第 229–237 段(text/06-ch03-chapter-3-variables-and-data-types.txt:231,搜「Raw string literals are enclosed」;:237,搜「C:\Users\John」)、第 171–181 段(text/06-ch03-chapter-3-variables-and-data-types.txt:177,搜「fn swap[T]」)。r#"..."# 是 Rust 语法;一行多变量声明是 JavaScript 式写法;[T] 泛型是 C#/Java 系语法——均非 Zig。 ↩↩