go中error是值而非异常,必须紧邻调用后用if err != nil检查并响应;应优先用errors.is/as判断,%w包装前须判空,固定错误用errors.new,动态内容才用fmt.errorf。

Go 里没有“解决 error”这回事——error 是值,不是异常,它不会自动中断执行,也不会被“捕获”或“吞掉”后就消失。你唯一能做的,是检查它、理解它、响应它。
if err != nil 必须紧跟调用,不能隔行或跳过
这不是风格问题,而是 Go 的控制流约束:不立刻处理,err 可能被后续赋值覆盖,或导致后续代码在无效状态下运行(比如对 nil 的 *os.File 调用 Read,直接 panic)。
-
err必须在函数调用后**紧邻一行**检查,不能隔开其他语句 - 绝大多数情况下,检查后应
return err或return nil, err,避免继续执行 - 若需资源清理(如已打开文件),把逻辑包进作用域:
if f, err := os.Open(path); err != nil { ... },或用defer配合条件判断
errors.Is 和 errors.As 才是安全的错误判断方式
用 == 比较或字符串匹配(strings.Contains(err.Error(), "timeout"))在错误被包装后必然失效;类型断言(err.(*os.PathError))只解一层,且易 panic。
-
errors.Is(err, fs.ErrNotExist):判断是否等于某个哨兵错误(支持嵌套穿透) -
errors.As(err, &pathErr):提取错误链中第一个匹配类型的实例(注意传指针,变量需在if外声明) - 自定义错误若想参与穿透,必须实现
Unwrap() error方法,返回被包裹的底层error
fmt.Errorf("%w") 包装错误时,右侧必须判空
%w 包装要求右侧参数是 error 类型,传 nil 会直接 panic,但很多函数返回的是 (T, error),error 可能为 nil。
- 错误包装前必须显式判空:
if err != nil { return fmt.Errorf("read config: %w", err) } - 不要用
%s或%v替代%w,否则原始错误类型和堆栈信息丢失 - 避免无意义的多层包装(比如中间件反复
fmt.Errorf("%w", err)),会拉长错误链、增加日志噪音
errors.New 与 fmt.Errorf 的使用边界很明确
二者都返回 error,但语义和性能不同:固定字符串错误用 errors.New 更轻量、更安全;动态内容才用 fmt.Errorf。
-
errors.New("invalid ID"):无变量、不需格式化,支持errors.Is精确比对 -
fmt.Errorf("failed to parse %q: %w", input, err):含变量或需嵌套原始错误时使用 - 误写
fmt.Errorf("invalid ID")属于冗余——做了格式解析却没用上占位符,还多一次内存分配
最常被忽略的一点:错误链不是越深越好。每层 fmt.Errorf("... %w", err) 都新建对象,高频 I/O 场景下可能成为性能瓶颈;如果只是记录日志,有时 errors.New + 明确上下文字段更高效、更可控。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











