标准库 — 数据结构、文件 I/O 与格式化¶
这一章是标准库巡礼,一条主线贯穿:std 没有一件东西替你藏内存。 ArrayList 递 allocator、HashMap 要 deinit、读文件要自己 free、 格式化字符串要 allocPrint + free——第 9 章的手艺,在这里变成工具。 四个展区:容器、文件 I/O、格式化、杂项(mem/随机/时间/排序)。
1. 这一章讲什么¶
第 9 章你用裸 alloc 手搓了字符串拼接(catAlloc);
这一章告诉你:那种活儿 std 里有现成的(ArrayList、std.mem),
但用法哲学不变——内存的账,每一笔记在你头上。
原书给 ArrayList 的判词就是全章的判词:「Memory is a resource, not a right.」1
2. 顶层全景与主线例子¶
容器 ArrayList(动态数组)│ HashMap(哈希表;字符串键用 StringHashMap)
文件 openFile → readToEndAlloc → free;createFile → writeAll → close → sync
文本 std.fmt.format / print / allocPrint + {s} {d} {x} {d:0>4}
杂项 std.mem(copy/set/eql/replace/split/tokenize)│ rand(伪随机 vs 加密随机)
│ time(时间戳/Timer,没有 DateTime)│ sort.block(原地、确定性)
图说:每个展区第一句都是「你要什么自己说,内存自己还」。
主线例子(贯穿容器与文件两区):打开一个文件 → 读进 ArrayList → 逐行处理 → 写回新文件 → sync → 关。每一步旁边是具体函数和「谁 free」。
3. 展区一:容器¶
3.1 ArrayList:动态数组,道德立场 Included¶
var list = ArrayList(u8).init(allocator); // 交出 allocator = 签下租约
try list.append(42); // 连追加一个数都可能 OOM,所以是 try
defer list.deinit(); // 不还 = 泄漏
init 只交租约不划地——第一个字节都不会提前分配;
append 可能失败(内存不够),错误显式上抛2。
配套的容量操作为性能服务:ensureTotalCapacity(1000)(先圈地)、
ensureTotalCapacityPrecise(精确到字节,嵌入式友好)、
shrinkAndFree(裁掉多租的)3。
两个风格化 API:appendAssumeCapacity(我保证有容量,炸了算我的——
缓冲区溢出即崩溃,是性能换责任的明牌);ArrayListUnmanaged
(结构体里不藏 allocator,每次操作手动传——给内核/WebAssembly
那种「allocator 像违禁品一样流通」的场景)4。
插入与删除的代价账(原书讲得很实在):insert(0, 99) 在头部插入是 O(n),
后面的元素全体右移,万级列表上就是「新型延迟」5;删除两兄弟:
orderedRemove(保序,像排队)和 swapRemove(把末尾元素拽进空档,
快、乱序,实时系统的选择)6。要给 C 接口用?
toOwnedSliceSentinel(0) 吐出带哨兵的切片——「想要哨兵?给。但生命周期归你管」7。
3.2 HashMap:酒馆斗殴与墓碑¶
var map = AutoHashMap(u32, u32).init(allocator);
defer map.deinit(); // 忘了 = 囤内存的龙
try map.put(42, 9001);
if (map.get(42)) |val| { ... } // 找不到返回 null → optional 解包
_ = map.remove(42); // 删,但留下「墓碑」
AutoHashMap 自动给键算哈希,但自定义键类型要提供两个「咒语」:
hash(键 → 数字)和 eql(两键是否相同)8。
字符串键有专门的坑:[]const u8 做键直接编译错误——
字符串可以按内容哈希、也可以按地址哈希,Zig 拒绝替你猜;用 StringHashMap,
它按内容哈希,像图书管理员9。
墓碑(tombstone)机制:remove 不真擦除,留个标记——
因为 Zig 用线性探测(linear probing,冲突时逐个看下一个槽位的算法),
需要墓碑防止搜索提前终止。墓碑堆积会让表变成「闹鬼墓地」,性能劣化;
map.rehash() 一次大扫除10。高频增删的负载下定期 rehash,CPU 缓存会感谢你11。
3.3 主线例子走查(读 → 改 → 写)¶
① const file = try std.fs.cwd().openFile("in.txt", .{});
② defer file.close();
③ const data = try file.readToEndAlloc(allocator, 1 << 20); // 上限 1 MB
④ defer allocator.free(data);
⑤ var list = std.ArrayList(u8).init(allocator);
⑥ defer list.deinit();
⑦ try list.appendSlice(data); // 或逐行处理:分割、过滤、重组
⑧ const out = try std.fs.cwd().createFile("out.txt", .{});
⑨ defer out.close();
⑩ try out.writeAll(list.items);
⑪ try out.sync(); // 关键写入后落盘
每笔内存的去向:③ 读出的 data 归你(④ 还);⑤ 的 list 归你(⑥ 还); ⑧ 的文件句柄归你(⑨ 关)。五个 defer,五个责任点——这就是第 9 章 「init/deinit 对」在 std 用户侧的 everyday 形态。
4. 展区二:文件 I/O¶
4.1 基本功¶
- 开:
std.fs.cwd().openFile("secret_plans.txt", .{ .read = true })—— 文件不存在、权限不足,全是显式错误,try/catch 伺候12; - 读:
readToEndAlloc(allocator, 上限)一口吞到文件尾(设上限防爆内存), 大文件改 buffered reader 按块读:readUntilDelimiterOrEof(&buffer, '\n')逐行13; - 写:
createFile+writeAll;写完sync()(落盘;syncDataOnly只刷数据), 防止「断电时数据还在缓冲区里」14; - 定位:
seekTo(0)倒带、getPos()问位置、seekBy(-10)相对跳—— 解析二进制格式的基本功15; - 权限:
chmod(0o644)(属主读写、众人只读),stat()查状态16; - 硬链接:
link(a, b)——两个文件名同一个数据体,删一个另一个还在; 备份系统爱用17。
4.2 失落卷轴(std.fs 的进阶面,原书专节)¶
| 招 | 干什么 | 注意 |
|---|---|---|
| 标志位 | .append(追加)、.exclusive(已存在则失败)、.truncate(打开即清空)、.read+.write 组合 |
「与文件系统的合同」 |
| mmap | std.os.mmap 把文件映射成内存,改内存即改文件 |
杂耍手雷:一步踏错就是段错误喷泉18 |
| 磁盘情报 | FileSystemStats 查剩余空间 |
嵌入式写固件前必查19 |
| 符号链接 | symLink 建链;链可能悬空,用前先 stat 目标 |
「It's a trap!」20 |
| EINTR 重试 | writeWithRetry:遇 error.Interrupted 就 continue |
网络文件系统、娇贵硬件的必备礼数21 |
5. 展区三:std.fmt 格式化¶
三件套:format(writer, 串, 参数)(写给任意 writer)、
std.debug.print(直出 stdout,侦察兵)、
allocPrint(造一个堆上的字符串,用完 free)22。
占位符带类型:{s} 字符串、{d} 整数、{x}/{X} 十六进制、{b} 二进制、
{d:.3} 小数点后三位、{d:0>4} 右对齐零填充到 4 位、{d:*<4} 左对齐星号填充23。
类型不匹配是编译错误——原书的测验:{d} 配 "5"(字符串)直接不过,
Zig 没有含糊的 %v24。
自定义类型的格式化:给结构体写一个 format 方法,
它就能进任何格式串——Monster{name="Lifetime Leak", hp=9999} 打印成
Lifetime Leak (HP: 9999)25。三个卖点(原书):编译期检查、
零隐藏分配(嵌入式/WASM 友好)、完全显式的控制26。
6. 展区四:随机、时间、排序、std.mem¶
6.1 随机:两把武器,别用错¶
std.Random.DefaultPrng |
std.crypto.random |
|
|---|---|---|
| 本质 | 确定性伪随机,种子固定则序列固定 | 操作系统级熵(/dev/urandom 一系) |
| 用途 | 游戏、模拟、可复现调试 | 密码、令牌、「可预测即失败」处 |
| 坑 | 种子可猜 = 「随机」可猜 | 杀鸡用牛刀,慢 |
原书的双关:别召唤克苏鲁来开泡菜坛子27。
6.2 时间:没有 DateTime,是故意的¶
timestamp()(秒,1970 起)、nanoTimestamp()(纳秒,基准点随意,测时专用)、
Timer(起表/读数,纳秒精度)28。算 30 天试用:now + 30*24*60*60——
原书顺便道歉:对不起二月,你很特别(天数不齐)。
溢出警报:大时长加法用饱和运算 +|(到顶就封顶,不崩不绕)29。
为什么不给 DateTime?时区、闰年、夏令时全是政治包袱,Zig 选择不给一刀切答案30。
6.3 排序与切分¶
std.sort.block(T, &arr, {}, comptime asc(T))——原地、无分配、确定性
(同样输入永远同样输出);自定义比较器就是一个 lessThan 函数,
降序写 a.score > b.score31。
std.mem.split(按定界符切,保留空段:CSV 的 "Zig,Rust,,C" 切出 4 段)
与 std.mem.tokenize(跳过空段、修剪空白,CLI 参数友好)的分工,
是解析代码的第一道口令32。
6.4 std.mem 速查(原书按用途组织)¶
copy(长度必须相等,防溢出的 memcpy)、set(填充/擦除敏感数据)、 eql(字节级相等,校验哈希用)、replace(堆上新串,记得 free)、 sliceAsBytes/bytesAsSlice(类型切片 ↔ 字节切片,序列化)、 alignForward(对齐到 16,SIMD 前用)、readInt/writeInt(显式大端/小端,解析 PNG 头)、 split/tokenize(见上)33。 原书给的挑战解(64 字节分块 + 原地替换 0xFF→0x00 + Timer 计时) 是这些工具的组合拳样板34。
7. 作者的判断与证据¶
可核的: 全部 API 签名、输出样例(Health: 0005、0xff、PI: 3.142)、
墓碑与 rehash 机制、EINTR 重试模式——都可跑可验231021。
立场: 全章修辞是「std 是道德立场不是工具箱」1;这是有倾向的写法 (std 也有便捷面,比如 AutoHashMap 的「Auto」),但方向和第 1 章一致,不算夸张。
8. 边界与局限¶
| 缺什么 | 说明 |
|---|---|
| ArrayList 的增长策略没讲 | 翻倍还是 1.5 倍、均摊复杂度,全章只字未提 |
| HashMap 的负载因子/扩容时机没讲 | rehash 何时自动发生,没有 |
| 文件 I/O 没有讲目录遍历、watch | walk、事件监听留给第 13 章 FileGuard 现学 |
| std.fmt 的性能与 comptime 格式化细节浅 | comptime 格式串的编译期检查机制没展开 |
| 没有 JSON/序列化 | std.json 是标准库重头之一,本章完全没出现 |
| 时间没有讲单调钟 vs 墙上钟的区别 | Timer 是单调钟这一关键性质没点名(只说了「arbitrary point」) |
9. 可带走的¶
主线例子一行: openFile → readToEndAlloc(带上限)→ free; ArrayList.init → append → deinit;createFile → writeAll → close → sync; 五个 defer 对应五笔账。
- ArrayList:init 递 allocator、append 要 try、deinit 必写;
insert(0,x)是 O(n);swapRemove快且乱序、orderedRemove慢且保序; - HashMap:字符串键用 StringHashMap;remove 留墓碑,堆积了
rehash(); - 文件:读带上限、写后
sync()、句柄 defer close;进阶面记住 mmap(危险)、FileSystemStats(嵌入式)、symlink 会悬空、EINTR 要重试; - std.fmt:
{s}/{d}/{x}类型分明,不匹配编译报错;{d:0>4}对齐填充; 自定义类型写个format方法就能进格式串; - 随机:可复现用
DefaultPrng(种子 42),安全用std.crypto.random; - 时间:没有 DateTime 是有意的;大时长加法用饱和
+|防溢出; - 切分:保留空段用 split,跳过空段用 tokenize;
- 排序:
sort.block原地、确定性,比较器自己写; - std.mem:copy 长度强制相等(防溢出 memcpy)、eql 比字节、 sliceAsBytes 做序列化、readInt 显式端序;
- 全章一句话:std 的每一件工具,都把第 9 章的内存责任原样交回你手上。
10. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| ArrayList init/append/契约 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:41(搜「ArrayList(u8).init」) · text/17-ch10-chapter-10-the-standard-library.txt:50(搜「list.append(42)」) |
| 容量三件套与 Unmanaged | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:61(搜「ensureTotalCapacity」) · text/17-ch10-chapter-10-the-standard-library.txt:75(搜「ArrayListUnmanaged」) |
| insert O(n) 与删除两兄弟 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:86(搜「Prepends 99」) · text/17-ch10-chapter-10-the-standard-library.txt:91(搜「swapRemove」) |
| 「资源不是权利」 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:106(搜「Memory is a resource」) |
| HashMap 基本操作 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:135(搜「AutoHashMap(u32, u32).init」) · text/17-ch10-chapter-10-the-standard-library.txt:154(搜「Tombstone」) |
| hash/eql 与 StringHashMap | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:173(搜「compile error」) · text/17-ch10-chapter-10-the-standard-library.txt:177(搜「StringHashMap」) |
| 墓碑与 rehash | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:180(搜「tombstone」) · text/17-ch10-chapter-10-the-standard-library.txt:185(搜「map.rehash」) |
| openFile 与 defer close | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:242(搜「secret_plans.txt」) |
| readToEndAlloc 与缓冲读 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:270(搜「readToEndAlloc」) · text/17-ch10-chapter-10-the-standard-library.txt:324(搜「readUntilDelimiterOrEof」) |
| createFile/writeAll/sync/seek | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:284(搜「createFile」) · text/17-ch10-chapter-10-the-standard-library.txt:335(搜「sync」) · text/17-ch10-chapter-10-the-standard-library.txt:345(搜「seekTo(0)」) |
| 二进制 I/O extern struct | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:302(搜「extern struct」) |
| chmod 与硬链接 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:369(搜「0o644」) · text/17-ch10-chapter-10-the-standard-library.txt:384(搜「link」) |
| 失落卷轴:mmap/stats/symlink/EINTR | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:436(搜「mmap」) · text/17-ch10-chapter-10-the-standard-library.txt:452(搜「FileSystemStats」) · text/17-ch10-chapter-10-the-standard-library.txt:460(搜「symLink」) · text/17-ch10-chapter-10-the-standard-library.txt:472(搜「writeWithRetry」) |
| format/print/allocPrint | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:517(搜「std.fmt.format」) · text/17-ch10-chapter-10-the-standard-library.txt:537(搜「allocPrint」) |
| 对齐填充与进制 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:547(搜「{d:0>4}」) · text/17-ch10-chapter-10-the-standard-library.txt:553(搜「0x{x}」) |
| 自定义 format | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:578(搜「pub fn format」) |
| {d} 配 "5" 的测验 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:599(搜「unread messages」) |
| 两种随机 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:641(搜「DefaultPrng.init(42)」) · text/17-ch10-chapter-10-the-standard-library.txt:653(搜「randomBytes」) |
| 时间 API 与 + | Chapter 10: The Standard Library | |
| split vs tokenize | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:696(搜「std.mem.split」) · text/17-ch10-chapter-10-the-standard-library.txt:705(搜「std.mem.tokenize」) |
| sort.block 与比较器 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:721(搜「sort.block」) · text/17-ch10-chapter-10-the-standard-library.txt:733(搜「sort by score」) |
| std.mem 速查 | Chapter 10: The Standard Library | text/17-ch10-chapter-10-the-standard-library.txt:771(搜「std.mem.copy」) · text/17-ch10-chapter-10-the-standard-library.txt:804(搜「sliceAsBytes」) · text/17-ch10-chapter-10-the-standard-library.txt:819(搜「readInt」) |
-
出处:「Chapter 10: The Standard Library」第 105–115 段(
text/17-ch10-chapter-10-the-standard-library.txt:106,搜「Memory is a resource」;text/17-ch10-chapter-10-the-standard-library.txt:115,搜「every allocation a debt」)。 ↩↩ -
出处:同章第 37–59 段(
text/17-ch10-chapter-10-the-standard-library.txt:41,搜「ArrayList(u8).init」;text/17-ch10-chapter-10-the-standard-library.txt:52,搜「Out of memory」)。 ↩ -
出处:同章第 60–71 段(
text/17-ch10-chapter-10-the-standard-library.txt:61,搜「ensureTotalCapacity」;text/17-ch10-chapter-10-the-standard-library.txt:66,搜「Precise」;text/17-ch10-chapter-10-the-standard-library.txt:69,搜「shrinkAndFree」)。 ↩ -
出处:同章第 54–59 与第 72–81 段(
text/17-ch10-chapter-10-the-standard-library.txt:56,搜「appendAssumeCapacity」;text/17-ch10-chapter-10-the-standard-library.txt:75,搜「ArrayListUnmanaged」)。 ↩ -
出处:同章第 83–93 段(
text/17-ch10-chapter-10-the-standard-library.txt:86,搜「Prepends 99」;text/17-ch10-chapter-10-the-standard-library.txt:89,搜「new form of latency」)。 ↩ -
出处:同章第 91–93 段(
text/17-ch10-chapter-10-the-standard-library.txt:91,搜「swapRemove」)。 ↩ -
出处:同章第 95–103 段(
text/17-ch10-chapter-10-the-standard-library.txt:97,搜「toOwnedSliceSentinel」)。 ↩ -
出处:同章第 159–178 段(
text/17-ch10-chapter-10-the-standard-library.txt:163,搜「Turn keys into numbers」;text/17-ch10-chapter-10-the-standard-library.txt:165,搜「impostors」)。 ↩ -
出处:同章第 173–178 段(
text/17-ch10-chapter-10-the-standard-library.txt:173,搜「compile error」;text/17-ch10-chapter-10-the-standard-library.txt:177,搜「StringHashMap」)。 ↩ -
出处:同章第 179–191 段(
text/17-ch10-chapter-10-the-standard-library.txt:180,搜「tombstone」;text/17-ch10-chapter-10-the-standard-library.txt:181,搜「linear probing」;text/17-ch10-chapter-10-the-standard-library.txt:185,搜「map.rehash」)。 ↩↩ -
出处:同章第 188–191 段(
text/17-ch10-chapter-10-the-standard-library.txt:190,搜「CPU cache」)。 ↩ -
出处:同章第 233–262 段(
text/17-ch10-chapter-10-the-standard-library.txt:242,搜「secret_plans.txt」)。 ↩ -
出处:同章第 265–276 与 319–328 段(
text/17-ch10-chapter-10-the-standard-library.txt:270,搜「readToEndAlloc」;text/17-ch10-chapter-10-the-standard-library.txt:324,搜「readUntilDelimiterOrEof」)。 ↩ -
出处:同章第 280–339 段(
text/17-ch10-chapter-10-the-standard-library.txt:284,搜「createFile」;text/17-ch10-chapter-10-the-standard-library.txt:335,搜「sync」)。 ↩ -
出处:同章第 343–351 段(
text/17-ch10-chapter-10-the-standard-library.txt:345,搜「seekTo(0)」)。 ↩ -
出处:同章第 362–376 段(
text/17-ch10-chapter-10-the-standard-library.txt:369,搜「0o644」)。 ↩ -
出处:同章第 380–387 段(
text/17-ch10-chapter-10-the-standard-library.txt:384,搜「link」)。 ↩ -
出处:同章第 433–448 段(
text/17-ch10-chapter-10-the-standard-library.txt:436,搜「mmap」;text/17-ch10-chapter-10-the-standard-library.txt:448,搜「segmentation fault fountain」)。 ↩ -
出处:同章第 450–456 段(
text/17-ch10-chapter-10-the-standard-library.txt:452,搜「FileSystemStats」)。 ↩ -
出处:同章第 457–468 段(
text/17-ch10-chapter-10-the-standard-library.txt:460,搜「symLink」;text/17-ch10-chapter-10-the-standard-library.txt:468,搜「Always check」)。 ↩ -
出处:同章第 470–483 段(
text/17-ch10-chapter-10-the-standard-library.txt:472,搜「writeWithRetry」;text/17-ch10-chapter-10-the-standard-library.txt:475,搜「Interrupted」)。 ↩↩ -
出处:同章第 509–538 段(
text/17-ch10-chapter-10-the-standard-library.txt:517,搜「std.fmt.format」;text/17-ch10-chapter-10-the-standard-library.txt:537,搜「allocPrint」)。 ↩ -
出处:同章第 542–563 段(
text/17-ch10-chapter-10-the-standard-library.txt:547,搜「{d:0>4}」;text/17-ch10-chapter-10-the-standard-library.txt:553,搜「0x{x}」;text/17-ch10-chapter-10-the-standard-library.txt:560,搜「{d:.3}」)。 ↩↩ -
出处:同章第 597–608 段(
text/17-ch10-chapter-10-the-standard-library.txt:599,搜「unread messages」)。 ↩ -
出处:同章第 568–593 段(
text/17-ch10-chapter-10-the-standard-library.txt:578,搜「pub fn format」;text/17-ch10-chapter-10-the-standard-library.txt:589,搜「Boss:」)。 ↩ -
出处:同章第 610–616 段(
text/17-ch10-chapter-10-the-standard-library.txt:612,搜「Compile-time checks」)。 ↩ -
出处:同章第 634–655 段(
text/17-ch10-chapter-10-the-standard-library.txt:641,搜「DefaultPrng.init(42)」;text/17-ch10-chapter-10-the-standard-library.txt:653,搜「randomBytes」;text/17-ch10-chapter-10-the-standard-library.txt:651,搜「pickle jar」)。 ↩ -
出处:同章第 658–670 段(
text/17-ch10-chapter-10-the-standard-library.txt:667,搜「timestamp()」;text/17-ch10-chapter-10-the-standard-library.txt:668,搜「nanoTimestamp」;text/17-ch10-chapter-10-the-standard-library.txt:670,搜「std.time.Timer」)。 ↩ -
出处:同章第 677–681 段(
text/17-ch10-chapter-10-the-standard-library.txt:679,搜「saturating math」)。 ↩ -
出处:同章第 662–665 段(
text/17-ch10-chapter-10-the-standard-library.txt:664,搜「political baggage」)。 ↩ -
出处:同章第 717–741 段(
text/17-ch10-chapter-10-the-standard-library.txt:721,搜「sort.block」;text/17-ch10-chapter-10-the-standard-library.txt:740,搜「deterministic」)。 ↩ -
出处:同章第 689–714 与 820–836 段(
text/17-ch10-chapter-10-the-standard-library.txt:696,搜「std.mem.split」;text/17-ch10-chapter-10-the-standard-library.txt:705,搜「std.mem.tokenize」)。 ↩ -
出处:同章第 758–836 段(
text/17-ch10-chapter-10-the-standard-library.txt:771,搜「std.mem.copy」;text/17-ch10-chapter-10-the-standard-library.txt:784,搜「std.mem.eql」;text/17-ch10-chapter-10-the-standard-library.txt:804,搜「sliceAsBytes」;text/17-ch10-chapter-10-the-standard-library.txt:819,搜「readInt」)。 ↩ -
出处:同章第 838–861 段(
text/17-ch10-chapter-10-the-standard-library.txt:841,搜「std.time.Timer.start」)。 ↩