应使用 %+v 展开错误链(需错误类型实现 fmt.formatter),%v 仅显示顶层消息,%s 强制调用 error();打印前须判 err != nil,避免输出 。
直接用 fmt.Println 或 fmt.Printf 打印 error 值,通常只显示错误文本,丢失上下文和底层类型信息;真要调试或记录错误,得用对函数、传对参数,否则日志里全是“failed: %v”这种无效内容。
为什么 fmt.Error 不是标准函数?
Go 里没有 fmt.Error 这个函数——这是常见误解。真正起作用的是 error 接口自带的 Error() 方法,它返回 string;fmt 包只是在格式化时自动调用它(比如用 %v 或 %s)。但注意:%v 对 error 类型默认调用 Error(),而 %+v 在某些错误类型(如 fmt.Errorf 带 %w 包装的)下才会展开堆栈或嵌套错误。
- 普通
errors.New("xxx"):用%v和%+v效果一样,都只输出字符串 -
fmt.Errorf("wrap: %w", err):只有%+v才会显示被包装的原始错误 - 第三方错误库(如
github.com/pkg/errors):依赖其自定义fmt.Formatter实现,%+v才有效
fmt.Printf 中该选 %v、%s 还是 %+v?
取决于你要不要错误链和位置信息:
-
%s:强制调用err.Error(),最保守,不触发任何额外行为,适合日志摘要行 -
%v:默认行为,对大多数error和%w包装的也只显示顶层消息 -
%+v:唯一能展开错误链的选项(前提是错误类型实现了fmt.Formatter),调试时推荐,但生产日志慎用——可能暴露敏感路径或内部结构
示例: