Go 错误是接口而非结构体,因需支持上下文定制;标准 error 接口仅含 Error() 方法;自定义错误可带字段便于类型断言;推荐用 errors.Is/As 处理嵌套错误,慎用 %w 包装,避免忽略错误或滥用 panic。

Go 语言里没有异常(exception),error 是一个接口类型,不是特殊语法糖——这意味着你得主动检查、显式返回、手动传递,不能靠 try/catch 隐藏控制流。
为什么 error 是接口而不是结构体?
因为 Go 鼓励你根据上下文定制错误行为。标准库定义为:type error interface { Error() string },只要实现了这个方法,就是合法的 error。
- 自定义错误常带字段(如
Code、Timestamp),方便下游做类型断言或结构化处理 -
fmt.Errorf默认返回的是*errors.errorString,不带额外信息,适合简单提示 - 用
errors.New创建的错误不可比较(底层是字符串指针),想用==判定需用errors.Is或自定义导出变量
如何正确判断和展开错误链?
从 Go 1.13 开始,errors.Is 和 errors.As 成为处理嵌套错误的标准方式,替代了旧式的字符串匹配或类型断言嵌套。
-
errors.Is(err, io.EOF)能穿透多层fmt.Errorf("failed: %w", err)找到原始错误 -
errors.As(err, &target)用于提取特定类型的错误值(比如自定义结构体),比if e, ok := err.(*MyError)更安全 - 避免写
if err != nil && strings.Contains(err.Error(), "timeout")—— 这种字符串解析脆弱且无法跨语言本地化
什么时候该用 fmt.Errorf 的 %w,什么时候不该?
%w 是错误包装(wrapping)操作符,仅在你需要保留原始错误语义、又想添加上下文时使用;滥用会导致错误链过长、日志冗余、调试困难。
立即学习“go语言免费学习笔记(深入)”;
- 推荐场景:HTTP handler 中包装数据库错误 →
fmt.Errorf("failed to fetch user %d: %w", id, dbErr) - 不推荐场景:重复包装同一错误(如中间件连续调用
fmt.Errorf("%w", err)多次)、或对已含充分上下文的错误再包一层 - 注意:
%w只接受一个error类型参数,传nil会 panic;若不确定,先判空:if dbErr != nil { return fmt.Errorf("...: %w", dbErr) }
常见陷阱:忽略错误、裸奔 log.Fatal、混淆 panic 与 error
Go 的错误处理哲学是「错误是值,不是事件」,所以每处 err 都该有明确归宿。
- 不要写
_, _ = strconv.Atoi(s)然后假装错误不存在——哪怕只是加个if err != nil { return err } - 避免在库函数里用
log.Fatal或os.Exit,这会让调用方失去控制权;应返回error交由上层决定是否终止 -
panic仅用于真正不可恢复的程序状态(如空指针解引用、非法状态机转移),不用于业务错误(如“用户未登录”“余额不足”)
最易被忽略的一点:错误变量命名别图省事叫 e 或 err 就完事——在多层嵌套或并发 goroutine 中,用 dbErr、httpErr、parseErr 能极大降低排查成本。错误不是装饰品,它是你留给下一个开发者最重要的上下文线索。










