直接回答:1.13 起的标准姿势:底层错误往上抛时用 fmt.Errorf("操作语境: %w", err) 包装,%w 把原错误挂进链;判断错误用 errors.Is(err, sentinel) 比对哨兵值(沿链逐层解包)、用 errors.As(err, &target) 提取具体类型。原则是:跨包边界用哨兵(var ErrNotFound = errors.New(...))或错误类型表达语义,调用方永远不该字符串匹配错误信息。
展开解析:设计分层:底层库定义哨兵错误供 Is 判断,或定义带字段的错误类型供 As 提取(如 *net.OpError);中间层只做包装添加上下文,不轻易吞错;顶层决定处理策略(重试、降级、返回 HTTP 状态码)。几个高频错误:%v 和 %w 用错导致链断掉;一个 Errorf 里多个 %w(1.20 起支持,Unwrap 返回 []error,Is/As 沿多支遍历);err == io.EOF 这种直等在包装后失效,必须 errors.Is。哨兵错误的命名惯例 Err 前缀、类型错误后缀 Error。与 panic 的分工:可预期的失败(网络、输入)走 error;程序不变量破坏才 panic;goroutine 里 panic 不设 recover 会拖垮整个进程,库代码尤其不该 panic。
追问方向:Unwrap 多错误时 Is 的遍历顺序?自定义错误类型如何实现 Is 方法定制匹配?errors.Join 的适用场景?
(约 430 字)