go 的错误处理是将 error 作为普通接口值显式传递和检查的设计:error 是内建接口,可自定义实现;函数必须声明并返回 error,调用方须显式处理;%w 支持错误链,errors.is/as 提供类型安全判断;error、panic、log.fatal 各司其职,不可混用。

Go 的错误处理不是“没异常所以凑合用”,而是主动选择把错误当作普通值来设计和传递——它不隐藏控制流,不跳转,不打断阅读节奏,只靠函数签名和显式检查就能让错误路径一目了然。
error 是接口,不是关键字
Go 里 error 是一个内建接口:type error interface{ Error() string }。它不特殊,不魔法,任何实现了 Error() 方法的类型都能当 error 用。
- 标准库用
errors.New("xxx")返回一个匿名结构体指针,它实现了Error() -
fmt.Errorf("msg: %w", err)包装时返回的是*wrapError类型,也实现了error接口 - 你可以自己写
type MyErr struct{ Code int; Msg string },再实现Error()方法,它就是合法error
这意味着:错误可以带字段、能比较、可序列化、能透传,完全受你控制——而不是被运行时或编译器劫持。
函数必须显式返回 error,调用方必须显式检查
Go 函数签名强制暴露失败可能性,比如 os.ReadFile(string) ([]byte, error)。这个 error 不是可选附件,是契约的一部分。
- 你不检查
err != nil,程序就可能用零值继续跑(比如空 slice、0 端口、空 struct),后续 panic 更难定位 - 静态分析工具如
errcheck能直接报出未检查的error,说明这种“显式”不是风格问题,是工程约束 - 不能像 Python 那样靠
try/except统一兜底——因为上层根本不知道下层哪一行可能返回什么错误
这不是限制,是把“错误在哪发生、谁该负责”钉死在调用点附近,避免错误语义漂移。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
%w 包装不是语法糖,是错误链的基础设施
Go 1.13 加入的 %w 动词,本质是让 error 支持嵌套,形成可解包的链式结构。
-
return fmt.Errorf("failed to parse config: %w", err)后,原始err被包裹进新错误,没丢上下文 - 下游可用
errors.Is(err, os.ErrNotExist)判断是否是文件不存在,不用字符串匹配 - 也可用
errors.As(err, &myErr)提取自定义错误类型,做差异化处理 - 但注意:
%w只能包装一个错误;多个错误要用errors.Join(err1, err2)
这背后没有栈帧捕获,也不依赖 panic 恢复——只是值的组合与解构,轻量且确定。
error 和 panic 的边界必须清晰
Go 把错误分三级:error(预期内失败)、panic(程序逻辑崩了)、log.Fatal(不可恢复,立刻退出)。混用会毁掉整个错误处理模型。
- 别在 HTTP handler 里对
json.Unmarshal失败直接panic——这是error场景,应该返回 400 - 别用
recover拦os.Open的permission denied——它本该是error,不是异常 -
panic应该只留给“不该发生但发生了”的事,比如 map 写入 nil、断言失败、空指针解引用
一旦把本该返回 error 的地方改成 panic,调用链就失去可控性,日志里只剩堆栈,没有业务上下文。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










