Ziglings 笔记 21: 错误即是值
错误不是异常
在 Ziglings 的第 21 个练习中,我第一次接触到了 Zig 的错误处理系统。 在此之前,我习惯了 try-catch(异常)或者检查返回值是否为 -1(C 语言风格)。Zig 告诉我:错误只是一种特殊的数据类型。
挑战:定义缺失的错误
代码中定义了一个名为 MyNumberError 的错误集,用于描述数字检查时的三种情况(太大、太小、等于4)。但是,错误集中漏掉了 TooSmall 的定义,导致编译器不认识它。
解决方案
这是修复后的代码:
const std = @import("std");
// 定义错误集 (Error Set)
// 这看起来非常像枚举 (Enum)
const MyNumberError = error{
TooBig,
TooSmall, // 补充了这里!
TooFour,
};
pub fn main() void {
const nums = [_]u8{ 2, 3, 4, 5, 6 };
for (nums) |n| {
std.debug.print("{}", .{n});
// 调用函数获取错误值
const number_error = numberFail(n);
// 像比较普通数值一样比较错误
if (number_error == MyNumberError.TooBig) {
std.debug.print(">4. ", .{});
}
if (number_error == MyNumberError.TooSmall) {
std.debug.print("<4. ", .{});
}
if (number_error == MyNumberError.TooFour) {
std.debug.print("=4. ", .{});
}
}
std.debug.print("\n", .{});
}
// 这个函数返回 MyNumberError 类型
// 这意味着它 *只能* 返回错误,不能返回正常值(这只是为了演示)
fn numberFail(n: u8) MyNumberError {
if (n > 4) return MyNumberError.TooBig;
if (n < 4) return MyNumberError.TooSmall;
return MyNumberError.TooFour;
}
核心知识点总结
1. 错误集 (error{...})
Zig 中的错误不是字符串,也不是对象,而是属于全局错误集的一部分。定义它就像定义枚举一样简单。有趣的是,整个程序中不同地方定义的同名错误(例如 error.FileNotFound)在底层会被视为同一个值。
2. 像值一样使用
在这个练习中,我们把 numberFail(n) 返回的错误赋值给了变量 number_error,然后用 if 语句去判断它。这体现了 Zig “Error is a value” 的哲学——你不需要特殊的语法去捕获它,你只需要像处理普通数据一样处理它。
后续预告:在这个练习中,函数只能返回错误。但在现实中,我们通常希望函数成功时返回结果,失败时才返回错误。下一篇我们将学习 Zig 强大的联合错误类型 !Type。