错误处理 — 枚举、联合与错误并集
错误处理 — 枚举、联合与错误并集
这一章是全书设计哲学的正主。 前面所有「透明」「把错误往早挪」的铺垫, 在这里收成一套机制:Zig 没有异常——一个函数可能失败,这件事写在它的返回类型里; 错误是值,可以列举、可以匹配、可以传递;
try一行传播,catch就地兜底,errdefer专管「出错时的清理」;出错后,错误返回追踪把错误走过的每一站打印给你。 为了讲透这套机制,本章先补三块地基:枚举、裸联合、带标签联合。
1. 这一章讲什么
链条位置:第 5 章的 divide 用 ?i32 表达「可能失败」,本章把它升级成完整的错误系统。
这是 Zig 区别于 C(返回值约定,人人可无视)和异常系语言(失败藏在调用栈的暗处)
的标志性设计,也是第 1 章「错误必须出现在函数签名里」那张安全网的兑现章。
2. 顶层全景
地基:enum(可穷举的命名值,与 switch 穷举检查互补)
union(一个变量,几种形态,但自己记不住现在是哪种)
tagged union(union + enum 标签:类型帮你记住现在是哪种)
正主:error{...} 错误集(一个函数可能出的所有错,写成一个集合)
ErrorSet!T 错误并集(返回值类型 = 一个值 或 一个错误)
try / catch / errdefer(三种处置姿势)
error return trace(错误的「行程单」)
图说:地基三件套解决「怎么表达几种可能」;正主解决「失败怎么成为类型的一等公民」。主线例子(原书自带,照走):四层调用链 main → topFunction → midFunction → bottomFunction,最底层 return error.FileNotFound,看错误怎么一步步传上来、
trace 怎么记录每一站;配一个 allocateResource 走查 errdefer 的「出错才清理」。
3. 地基一:枚举(enum)
3.1 解决什么问题
魔数(magic number) 之病:代码里到处散落 if status == 200、return -1,
数字的含义只在写代码的人脑子里。枚举给一组相关的值起名字1:
const Day = enum { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };枚举成员底层从 0 开始的整数,用内建函数 @intFromEnum 取出来:
Day.Wednesday 是 day number 2(从 0 数)2。也可以显式指定底层值,
比如 HTTP 状态码:OK = 200, NotFound = 404, InternalServerError = 5003——
读者不用再背数字。
3.2 枚举的四件扩展(照原书的顺序收)
- 方法:枚举可以带函数。
TrafficLight枚举挂一个isSafeToGo(self), 判断self == TrafficLight.Green4; - 与 switch 配对:对枚举 switch,Zig 的穷举检查强制你处理每个成员—— 漏一个编译错误。这是对第 4 章「穷举」性质的兑现:枚举越界新增,switch 跟着报错5;
- 枚举字面量:
const day: Day = .Saturday;——类型已知时,成员名前的Day.可以省,一个点号代替6。注意:省略有前提(类型已知); 没有类型标注的.Friday只是一个「枚举字面量」,还不属于任何枚举7; - 非穷举枚举(向前兼容):普通枚举 + switch 穷举,有个工程矛盾——
库的枚举将来新增成员,你代码里穷举的 switch 就编译不过了8。
解法是声明时带整数标签类型 + 一个
_占位:enum(u16) { Success = 0, Failure = 1, _ }。_告诉编译器「还有未知值会出现」,于是 switch 里必须写_ =>兜底分支9。
3.3 运行时内省
两个内建函数,本章立名字:@tagName 返回枚举值的字符串名字
(Day.Tuesday → "Tuesday")10;@typeInfo 在编译期返回类型的完整结构,
可以枚举出一个类型的所有字段11。这是 comptime 反射的入口,第 12 章还会见到。
判断(我们的,不是书里的): 「非穷举枚举 +
_占位」是本章最容易被略过、 但对库作者最重要的一节。它回答的是一个真实的工程问题:穷举检查在「库的演化」 面前是双刃剑——它保护调用方不漏情况,也把库的任何新增变成调用方的编译错误。 Zig 的选择是把这个矛盾显式化:默认穷举(安全),要演化就声明非穷举(自觉放弃部分检查)。 这和第 1 章的处方一字不差:没有免费的默认值,选择摆在明处。 如果错,会错在: 如果团队里没人记得「这个枚举声明了非穷举」,_兜底分支可能写成空操作,于是「前向兼容」退化成「静默吞掉新错误码」—— 安全网仍在,但兜住的东西没人看。
4. 地基二:联合(union)
4.1 裸联合:一个变量,几种形态
联合是一种「同一时刻只装得下一种东西、但可以是好几种之一」的类型12:
const Data = union {
intValue: i32,
floatValue: f64,
textValue: []const u8,
};
var inputData = Data{ .intValue = 42 }; // 此刻装着整数
inputData = Data{ .floatValue = 3.14 }; // 整体重赋,改装浮点
inputData = Data{ .textValue = "Hello, Zig!" }; // 再改装字符串和内层的 struct(结构体:所有字段同时存在)正相反:union 的所有字段共享同一块内存,
所以同时只能激活一个。省内存,代价是:语言不知道现在激活的是哪个。
访问没激活的字段,运行期 panic,报错原文照引:
access of union field 'floatValue' while field 'intValue' is active13。
要换激活字段,必须整体重赋一个新的 union 值14。
4.2 带标签联合(tagged union):union + enum
裸联合的「不知道激活了谁」正是第 1 章要消灭的「不透明」。 Zig 的解:给 union 配一个 enum 标签,类型自己记住现在是哪个字段15:
const Result = union(enum) {
Success: i32,
Error: []const u8,
};
fn calculate(input: i32) Result {
if (input >= 0)
return Result{ .Success = input * 2 } // 非负:成功,值翻倍
else
return Result{ .Error = "Input must be non-negative" };
}
// 使用:对标签 switch,Zig 穷举检查逼你处理每一种
switch (calculate(-5)) {
.Success => |value| print("Calculation result: {d}\n", .{value}),
.Error => |errMsg| print("Error: {s}\n", .{errMsg}),
}calculate(-5) → 返回 Error 分支,switch 匹配 .Error,解包出字符串16。
三个操作细节(原书都给了):switch 的分支捕获写法 |value| 拿到载荷;
要改载荷,用 |*value| 拿到可变指针再 value.* += 517;
union 也能挂方法(用 @tagName(self) 判断激活字段)18;
字面量可以省略类型名,靠推断:const num = .{ .intValue = 256 };19。
带标签联合就是「第 4 章 optionals 的 generalized 版」:?i32 本质上等价于
union(enum) { value: i32, none }。这个观察原书没明说,但解释了为什么
Zig 的类型工具感觉是一套东西的不同切面(补充,来自通用知识)。
5. 正主:错误集与错误并集
5.1 错误集(error set):把「可能出哪些错」写成类型
const NetworkError = error{
ConnectionLost,
Timeout,
InvalidResponse,
};错误集是专为错误准备的枚举:列出这个领域可能发生的所有失败20。
它的价值不在运行时,在签名:读到 NetworkError!void 的人,
确切知道 connectToServer 会出哪几种错——「一种一个不准、量身定制」,
而不是所有函数共享一个含糊的 Exception21。
5.2 错误并集(error union):返回值或错误
把错误集和一个普通类型用 ! 拼起来,就是错误并集:
fn parseFloat(input: []const u8) ParseError!f64 { ... }读法:这个函数返回一个 f64,或者返回 ParseError 里的一个错误。
![]const u8 前不写错误集名时,是「推断错误集」——编译器替你把函数体里
可能出现的错误收集起来22。
那个 ! 值得专门一记(原书有专门的注释框):在 Zig 里,! 不是「逻辑非」,
在函数签名里它专表「可能返回错误」23。这是全书出镜率最高的符号之一。
5.3 处置姿势一:try——「失败就替我把错误传上去」
pub fn main() !void {
const data = try fetchData("https://example.com"); // 此 URL 为原书示例(我们查阅于 2026-10-19,仅作占位)
...
}try 的语义一句话:成功就把值解开给我;失败就 return 这个错误,替我结束当前函数24。
它是「传播」的标准姿势——和第 5 章主线例子里的错误链配合,看主线例子的第一步:
bottomFunction: return error.FileNotFound ← 错误诞生
↑ try midFunction 失败 → return error.FileNotFound
↑ try topFunction 失败 → return error.FileNotFound
↑ try main 失败 → 程序以错误退出
图说:try 是「逐层上交」的语法糖,每一层只写一词,不写 if、不写 return。5.4 处置姿势二:catch——就地处理,或给个默认值
// 就地处理
_ = fetchData("https://example.com") catch |err| { // 此 URL 为原书示例(我们查阅于 2026-10-19,仅作占位)
print("Failed: {s}\n", .{@errorName(err)});
};
// 或给默认值(失败就当 0.0)
const value = std.fmt.parseFloat(f64, "not a number") catch 0.0;catch 接住错误,接住的错误对象用 |err| 命名,@errorName(err) 打出错误名25。
想丢弃返回值时,前面要加 _ =(Zig 不允许忽略返回值——又一个「不许假装没看见」)。
错误集可以相套:小错误集能自动升级成大错误集——
NetworkError 是 GeneralError 的子集,所以 GeneralError!void 的函数
可以直接 try 一个 NetworkError!void 的调用26。这让「底层具体、上层笼统」
的层次设计成立。
黑暗面(连着第 5 章):可以确定不会失败时,可以写 catch unreachable——
失败就 panic(Debug)或未定义行为(Release)27。判据和 unreachable 一样:
「被别处保证」,不是「我觉得」。
5.5 处置姿势三:errdefer——只在出错时执行的清理
第 5 章的 defer 是「出作用域必执行」;errdefer 是**「出作用域且带着错误时才执行」**28。
主线例子走查(分配内存的经典场景):
fn allocateResource(allocator: *std.mem.Allocator) !*u8 {
const buffer = try allocator.alloc(u8, 1024); // ① 申请 1024 字节
errdefer allocator.free(buffer); // ② 登记:出错就释放
performOperation(buffer) catch |err| { // ③ 后续操作可能失败
return err; // 失败 → 触发 errdefer
};
return buffer; // ④ 成功 → errdefer 不执行
}| 路径 | 执行到哪 | errdefer 是否执行 |
|---|---|---|
| performOperation 成功 | ④ 返回 buffer | 否——内存归调用方 |
| performOperation 失败 | ③ return err | 是——buffer 被释放,不泄漏 |
把「申请」和「出错才回收」在源码里写成相邻两行,泄漏从「可能性」变成 「结构上不可能」:只要申请成功,无论后面怎么失败,释放都已登记。 这就是 defer 家族和第 1 章「透明」的合奏:资源的生命周期从控制流里凸出来, 不用读者在脑内模拟所有返回路径。
6. 错误返回追踪:错误的行程单
6.1 它解决什么
传统栈追踪(stack trace)告诉你爆炸发生在哪,不告诉你炸弹怎么运到的。 Zig 的 error return trace 记录的是后者:错误沿调用链经过的每一站29。
用主线例子看产出。代码:
pub fn main() !void { try topFunction(); }
fn topFunction() !void { try midFunction(); }
fn midFunction() !void { try bottomFunction(); }
fn bottomFunction() !void { return error.FileNotFound; }程序以错误退出时,你看到的是一份「叙述」而不是一个「地址」:
Error: FileNotFound
in function bottomFunction
called by midFunction
called by topFunction
called by main每一站都留名30。排障时你不用猜「是谁传上来的」,直接从诞生点 (bottomFunction 里那行 return)开始查。
6.2 开关在哪
和第 1 章的四档表完全同构:Debug / ReleaseSafe 默认开启;ReleaseFast /
ReleaseSmall 默认关闭(省性能)31。没有 trace 的构建里,错误处理照常工作,
只是少了行程单;anyerror(全局错误集,所有错误的并集)在那种情况下仍可兜底32。
判断(我们的,不是书里的): error return trace 是本章最被低估的机制。 异常系语言的栈追踪在「错误对象被创建的那一刻」最详细,而 Zig 的错误是值、 沿 return 手动传播——每过一层都是一次「显式的交接」,记录交接成本极低、信息极准。 这是「没有异常」这个选择换来的红利:传播路径上没有隐形的栈展开, 所以每一步都看得见。它反过来也说明了 try 的设计为什么值: 因为传播是显式语法,trace 才能精确到词。 如果错,会错在: 如果某段代码用
catch接住错误又返回另一个错误, trace 记录的是新错误的行程,旧错误的来路会断——「改宗」错误时, 靠 trace 是查不到最初根源的,需要日志或手动把原错误附带上。
7. 作者的判断与证据
可核的: 全部语法和报错文本(裸联合访问 inactive 字段的 panic 原文13、
! 的签名语义23、try/catch/errdefer 的行为2428)可直接跑代码验证;
错误集子集→超集的自动升级26;trace 的默认开启档位31。
立场: 「错误值是你的 accountability partner(问责伙伴)——不许你假装没事」33; 「错误集让失败模式清晰、结构化、专业化,没有含混的错误码」34。 这两句是作者对 Zig 错误模型的价值宣言,同时也是对异常这套做法的批评 (失败藏在调用栈暗处、签名里看不见)。宣言成立,但注意它略过了成本: 每一个可能失败的调用点都要做出处置选择(try / catch / 忽略报错), 在频繁改动的原型代码里,这是真实的心理负担——C 的「先不管返回值」在 Zig 里编译都过不了。
8. 最佳实践(原书四条)与我们的增补
原书四条35:
- 用显式的、具体的错误类型——别造一个笼统的
error.Failed万物兜底; - defer 管常规清理,errdefer 管出错清理——分工明确;
- catch 优雅兜底,try 可预期地传播——每个调用点二选一,别发明第三种;
- 用带标签联合给错误处理加结构——多形态结果用 tag 表达。
我们的增补(不在书里):第 3 条有个没写明的推论——传播链别太长。 try 让传播零成本,代价是错误可能在六七层之后才第一次被 catch, trace 再长也要人来读。经验法则:跨「模块边界」时落一次 catch, 模块内部放心 try 传(补充,来自通用工程经验)。
9. 边界与局限
| 缺什么 | 说明 |
|---|---|
| 错误集的并集/交集语法没讲 | 实际写库时常用 `error{A} |
| trace 和 catch 的交互(改宗断链)没讲 | 见 §6 判断块——实际排障最常踩的坑,原书未提 |
try 在 defer/errdefer 里的行为没展开 | defer 里能不能 try、errdefer 和 try 叠加的登记顺序,留给读者自己试 |
| 自定义错误携带数据没有 | Zig 的惯例是「错误 + 上下文分开传」或带标签联合,本章只用字符串消息示例,惯例没总结 |
| 31 道章末题是全书面之最 | 题量远超其他章36,但填空选择题为主,只有「为什么 Zig 不许忽略错误」这类关键问题(第 30/31 题其实是下一章的广告)没有对应的深度题 |
| 和 optionals 的配合语焉不详 | try 不能用于 ?T(orelse try 或 `if (x) |
9.5 加深一层:原书一句带过、但值得摊开的三件事
这一节是我们补的台阶(标注来源),原书在这些地方只用了暗示。
9.5.1 异常到底差在哪(先讲清对手)
「Zig 没有异常」要听懂,得先知道异常是什么。异常(exception)是异常系语言 (C++、Java、Python、C#…)的失败机制:失败时「抛出」一个异常对象, 运行时在调用栈上逆向逐层弹出(行话叫栈展开,stack unwinding), 直到有人「接住」(try/catch 块)。问题在于:
| 异常 | Zig 错误值 | |
|---|---|---|
| 签名里看得见吗 | 看不见(除非额外标注) | !T 明写 |
| 传播方式 | 运行时栈展开,隐式 | try 逐层显式上交 |
| 失败路径的记录 | 栈追踪只到抛出点 | error return trace 记录每一站 |
| 零成本抽象 | 不是(有运行时开销,哪怕没异常发生) | 是(普通返回值,零运行时机制) |
「零成本」是 Zig 选择的硬核理由:没有异常发生时,异常机制本身不花一分钱 (补充,不在书里,来自 Zero-Cost Exceptions 讨论的通行结论;C++ 表格式异常处理也接近零成本, 但语言不强制你处理——看得见和零成本在 Zig 里是同时成立的)。
9.5.2 错误并集在内存里是什么
ParseError!f64 不是魔法:它是一个带标签的联合——正常时装 f64,
失败时装错误码。这和 §4 的 tagged union 是同一个东西,编译器帮你拼好了而已。
知道这个等价关系,两件事立刻想通:为什么能 switch 匹配错误、
为什么 error return trace 能在每一层留下记录(每层 return 都是一次普通的函数返回,
返回的是一个普通值)。
9.5.3 错误与 optional 的配合(原书没写、代码里天天见)
?T 表达「可能没有值」,!T 表达「可能失败」,两者会同时出现:
函数「找东西」常常写成 !?Item(失败或没找到)或 ?Item(不失败但可能没找到)。
配合的固定套路:
const item = (try findItem(key)) orelse return error.NotFound; // 先 try 错误,再 orelse 处理空
const opt = findItem(key) catch |err| switch (err) { ... }; // 先 catch 错误,再拿 optional先剥哪一层由你定,规则只有一条:每一层剥的时候都在场——不存在「两种失败混在一起没人管」的状态。 (补充,不在书里,来自 Zig 代码惯例。)
10. 可带走的
主线例子,一行走完: bottomFunction 里 return error.FileNotFound →
try 逐层上交 → main 退出 → trace 打印四站行程单;
allocateResource:申请 → errdefer free 登记 → 后续失败 → errdefer 触发 → 不泄漏。
- Zig 没有异常:可能失败的函数把这件事写进返回类型(
!T),失败路径在签名上可见; - error set 是「这个函数可能出哪些错」的显式清单,像枚举一样可 switch、可穷举检查;
!T读法:返回值,或一个错误;!在签名里专表错误,不是逻辑非;- try = 成功取值、失败替我 return;catch = 就地接错误,或给默认值;
- 小错误集自动升级成大错误集——底层具体、上层笼统,层次设计成立;
- errdefer 只在「带着错误离开」时执行——「申请-登记释放」两行相邻写,泄漏结构性地不可能;
- 裸联合共享内存、不知道激活字段,访问错了运行期 panic;带标签联合由类型记住, 配 switch 穷举检查,是「多形态结果」的安全表达;
- 错误返回追踪记录错误经过的每一站(Debug/ReleaseSafe 默认开)——看到的不只是爆炸点, 还有炸弹的来路;
catch unreachable的判据和 unreachable 相同:被别处保证,不是我觉得;- 处置三姿势之外没有第四种:每个失败调用点,要么 try、要么 catch、要么编译报错—— 「假装没看见」不是选项。
11. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 错误处理哲学(问责伙伴) | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:26(搜「first-class citizens」) · text/12-ch06-chapter-6-error-handling.txt:628(搜「accountability partner」) |
| 枚举与 @intFromEnum | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:79(搜「starting from zero」) · text/12-ch06-chapter-6-error-handling.txt:90(搜「day number 2」) |
| 自定义枚举值 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:95(搜「OK = 200」) |
| 枚举方法 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:119(搜「isSafeToGo」) |
| 枚举 + switch | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:143(搜「switch (day)」) · text/12-ch06-chapter-6-error-handling.txt:152(搜「TGIF」) |
| 枚举字面量 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:160(搜「const day: Day = .Saturday」) · text/12-ch06-chapter-6-error-handling.txt:170(搜「just an enum literal」) |
| 非穷举枚举 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:209(搜「This underscore is crucial」) · text/12-ch06-chapter-6-error-handling.txt:217(搜「catch-all case」) |
| @tagName 与 @typeInfo | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:244(搜「@tagName(day)」) · text/12-ch06-chapter-6-error-handling.txt:254(搜「@typeInfo(Day)」) |
| 裸联合定义 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:279(搜「const Data = union」) · text/12-ch06-chapter-6-error-handling.txt:285(搜「only one of them」) |
| 访问 inactive 字段 panic | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:319(搜「access of union field」) |
| 整体重赋换激活字段 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:325(搜「Data{ .floatValue = 2.718 }」) |
| 带标签联合 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:338(搜「union(enum)」) · text/12-ch06-chapter-6-error-handling.txt:351(搜「Result{ .Success = input * 2 }」) |
| switch 修改载荷 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:380(搜「 |
| union 方法与匿名字面量 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:407(搜「@tagName(self) ==」) · text/12-ch06-chapter-6-error-handling.txt:437(搜「.{ .intValue = 256 }」) |
| 错误集 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:465(搜「const NetworkError = error{」) |
| fetchData 与 ! 语义 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:477(搜「fn fetchData」) · text/12-ch06-chapter-6-error-handling.txt:486(搜「may return an error from its error set」) |
| ! 符号专讲 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:507(搜「indicate that a function may return an error」) |
| try 的语义 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:491(搜「try keyword attempts」) |
| catch 就地处理 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:511(搜「catch |
| 错误并集 parseFloat | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:533(搜「ParseError!f64」) |
| 错误集升级 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:584(搜「coerced into GeneralError」) |
| catch 默认值与 catch unreachable | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:593(搜「catch 0.0」) · text/12-ch06-chapter-6-error-handling.txt:600(搜「catch unreachable」) |
| errdefer | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:606(搜「only if an error is returned」) · text/12-ch06-chapter-6-error-handling.txt:613(搜「errdefer allocator.free」) |
| 错误返回追踪 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:663(搜「play-by-play」) · text/12-ch06-chapter-6-error-handling.txt:685(搜「return error.FileNotFound」) |
| trace 示例输出 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:705(搜「Error: FileNotFound」) |
| trace 默认档位 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:715(搜「Debug and ReleaseSafe builds」) |
| anyerror | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:725(搜「global error set anyerror」) |
| 最佳实践四条 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:741(搜「Use explicit error types」) |
| 章末 31 题 | Chapter 6: Error Handling | text/12-ch06-chapter-6-error-handling.txt:787(搜「choose the correct answer」) · text/12-ch06-chapter-6-error-handling.txt:997(搜「Answers」) |
Footnotes
-
出处:「Chapter 6: Error Handling」第 47–66 段(
text/12-ch06-chapter-6-error-handling.txt:49,搜「magic numbers」)。原文:散布魔数是「确保你未来的自己恨你」的好办法。 ↩ -
出处:同章第 79–90 段(
text/12-ch06-chapter-6-error-handling.txt:79,搜「starting from zero」;text/12-ch06-chapter-6-error-handling.txt:90,搜「day number 2」)。 ↩ -
出处:同章第 92–109 段(
text/12-ch06-chapter-6-error-handling.txt:95,搜「OK = 200」)。 ↩ -
出处:同章第 110–132 段(
text/12-ch06-chapter-6-error-handling.txt:119,搜「isSafeToGo」)。 ↩ -
出处:同章第 134–152 段(
text/12-ch06-chapter-6-error-handling.txt:143,搜「switch (day)」;text/12-ch06-chapter-6-error-handling.txt:152,搜「TGIF」)。 ↩ -
出处:同章第 154–166 段(
text/12-ch06-chapter-6-error-handling.txt:160,搜「const day: Day = .Saturday」)。 ↩ -
出处:同章第 168–170 段(
text/12-ch06-chapter-6-error-handling.txt:170,搜「just an enum literal」)。 ↩ -
出处:同章第 172–201 段(
text/12-ch06-chapter-6-error-handling.txt:200,搜「fail to compile」)。 ↩ -
出处:同章第 203–231 段(
text/12-ch06-chapter-6-error-handling.txt:209,搜「This underscore is crucial」;text/12-ch06-chapter-6-error-handling.txt:217,搜「catch-all case」)。 ↩ -
出处:同章第 239–248 段(
text/12-ch06-chapter-6-error-handling.txt:244,搜「@tagName(day)」)。 ↩ -
出处:同章第 250–265 段(
text/12-ch06-chapter-6-error-handling.txt:254,搜「@typeInfo(Day)」)。 ↩ -
出处:同章第 273–286 段(
text/12-ch06-chapter-6-error-handling.txt:279,搜「const Data = union」;text/12-ch06-chapter-6-error-handling.txt:285,搜「only one of them」)。 ↩ -
出处:同章第 309–321 段(
text/12-ch06-chapter-6-error-handling.txt:319,搜「access of union field」;text/12-ch06-chapter-6-error-handling.txt:320,搜「while field 'intValue' is active」)。 ↩ ↩2 -
出处:同章第 323–328 段(
text/12-ch06-chapter-6-error-handling.txt:325,搜「Data{ .floatValue = 2.718 }」)。 ↩ -
出处:同章第 330–344 段(
text/12-ch06-chapter-6-error-handling.txt:334,搜「combines a union with an enum」)。 ↩ -
出处:同章第 345–371 段(
text/12-ch06-chapter-6-error-handling.txt:351,搜「Result{ .Success = input * 2 }」)。 ↩ -
出处:同章第 373–394 段(
text/12-ch06-chapter-6-error-handling.txt:380,搜「|*value|」)。 ↩ -
出处:同章第 396–421 段(
text/12-ch06-chapter-6-error-handling.txt:407,搜「@tagName(self) ==」)。 ↩ -
出处:同章第 423–447 段(
text/12-ch06-chapter-6-error-handling.txt:437,搜「.{ .intValue = 256 }」)。 ↩ -
出处:同章第 459–488 段(
text/12-ch06-chapter-6-error-handling.txt:465,搜「const NetworkError = error{」;text/12-ch06-chapter-6-error-handling.txt:460,搜「similar to an enum」)。 ↩ -
出处:同章第 633–646 段(
text/12-ch06-chapter-6-error-handling.txt:643,搜「precise, structured, and professional」)。 ↩ -
出处:同章第 474–488 段(
text/12-ch06-chapter-6-error-handling.txt:477,搜「fn fetchData」;text/12-ch06-chapter-6-error-handling.txt:486,搜「may return an error from its error set」)。 ↩ -
出处:同章第 502–507 段(
text/12-ch06-chapter-6-error-handling.txt:507,搜「indicate that a function may return an error」)。 ↩ ↩2 -
出处:同章第 490–500 段(
text/12-ch06-chapter-6-error-handling.txt:491,搜「try keyword attempts」)。 ↩ ↩2 -
出处:同章第 509–518 段(
text/12-ch06-chapter-6-error-handling.txt:511,搜「catch |err|」)与第 590–596 段(text/12-ch06-chapter-6-error-handling.txt:593,搜「catch 0.0」)。 ↩ -
出处:同章第 562–588 段(
text/12-ch06-chapter-6-error-handling.txt:584,搜「coerced into GeneralError」)。 ↩ ↩2 -
出处:同章第 598–603 段(
text/12-ch06-chapter-6-error-handling.txt:600,搜「catch unreachable」)。 ↩ -
出处:同章第 605–625 段(
text/12-ch06-chapter-6-error-handling.txt:606,搜「only if an error is returned」;text/12-ch06-chapter-6-error-handling.txt:613,搜「errdefer allocator.free」)。 ↩ ↩2 -
出处:同章第 648–671 段(
text/12-ch06-chapter-6-error-handling.txt:663,搜「play-by-play」)。 ↩ -
出处:同章第 703–712 段(
text/12-ch06-chapter-6-error-handling.txt:705,搜「Error: FileNotFound」)。 ↩ -
出处:同章第 714–718 段(
text/12-ch06-chapter-6-error-handling.txt:715,搜「Debug and ReleaseSafe builds」)。 ↩ ↩2 -
出处:同章第 723–726 段(
text/12-ch06-chapter-6-error-handling.txt:725,搜「global error set anyerror」)。 ↩ -
出处:同章第 627–631 段(
text/12-ch06-chapter-6-error-handling.txt:628,搜「accountability partner」)。 ↩ -
出处:同章第 633–646 段(
text/12-ch06-chapter-6-error-handling.txt:639,搜「expected but also defined and documented」)。 ↩ -
出处:同章第 739–748 段(
text/12-ch06-chapter-6-error-handling.txt:741,搜「Use explicit error types」)。 ↩ -
出处:同章第 785–1028 段(
text/12-ch06-chapter-6-error-handling.txt:787,搜「choose the correct answer」;text/12-ch06-chapter-6-error-handling.txt:997,搜「Answers」)。 ↩