%w 包装错误可保留原始错误类型、堆栈和可判定性,而 %v 或字符串拼接会导致 errors.is/as 失效;正确用法是 fmt.errorf("msg: %w", err),且自定义错误须实现 unwrap() 返回 error 类型。

用 %w 包装错误,而不是 %v 或字符串拼接
错误链断裂的最常见原因,就是把 fmt.Errorf("xxx: %v", err) 当成包装——它只是把原始错误转成字符串再拼进去,err 的类型、堆栈、可判定性全丢了。errors.Is 和 errors.As 会直接失效。
- ✅ 正确写法:
return fmt.Errorf("load config: %w", err)——%w必须是最后一个动词,且只接受一个error类型参数 - ❌ 错误写法:
return fmt.Errorf("load config: %s", err.Error())或return errors.New("load config: " + err.Error()) - ⚠️ 多层包装要嵌套:想加两层上下文,得写成
fmt.Errorf("api layer: %w", fmt.Errorf("db layer: %w", origErr)),不能塞多个%w
自定义错误类型必须实现 Unwrap() 方法
光有 Err error 字段没用。如果结构体里嵌了个底层错误,但没提供 Unwrap(),标准库就钻不下去,errors.Is(err, sql.ErrNoRows) 永远返回 false。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- ✅ 必须显式实现:
func (e *MyError) Unwrap() error { return e.Err } - ❌ 不要返回
nil除非真没包装(比如ValidationError);也不要加判断逻辑,如if e.Code == 404 { return e.Err },这会破坏递归展开 - ⚠️
Unwrap()只需返回直接包裹的那一个错误(单级),标准库自己负责递归遍历整条链
检查错误要用 errors.Is 和 errors.As,别用 == 或字符串匹配
哨兵错误(如 var ErrNotFound = errors.New("not found"))一旦被 %w 包装过,指针就变了,err == ErrNotFound 立刻失效;而 strings.Contains(err.Error(), "not found") 更危险——可能误判、漏判,还暴露实现细节。
- ✅ 判定是否为某类错误:
if errors.Is(err, sql.ErrNoRows) { ... } - ✅ 提取具体类型:
var perr *os.PathError; if errors.As(err, &perr) { ... } - ⚠️ 日志里慎用
fmt.Sprintf("%+v", err):开发期有用,但上线后可能泄露路径、变量名甚至内存地址;生产建议用err.Error()输出顶层消息,调试详情走单独 debug 日志通道
HTTP handler 中错误不能裸奔,要脱敏并结构化响应
把 os.PathError 或 SQL 错误直接 http.Error(w, err.Error(), http.StatusInternalServerError) 扔给前端,既不安全也不友好。用户不需要知道“no such file”,只需要知道“配置加载失败”;监控系统更需要结构化的 Code 和 RequestID。
- ✅ 统一响应结构:
type ErrorResponse struct { Code string `json:"code"` Message string `json:"message"` RequestID string `json:"request_id,omitempty"` } - ✅ handler 内先记录带上下文的日志:
log.Errorw("failed to serve user", "err", err, "user_id", id, "req_id", reqID) - ⚠️ 不要在 middleware 里
recover()后统一返回 500:要区分是编程错误(该修代码)还是外部依赖失败(可降级),后者应走业务码而非 500
Unwrap() 方法的签名一致性——它必须返回 error,不能是 interface{} 或其他类型,否则整个链在 errors.As 时静默失败。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










