Documentation
¶
Overview ¶
Package errors 提供线程安全的多错误聚合。
支持 errors.Is 链式检查,使用 sync.Pool 优化字符串格式化。
快速接入 ¶
var err error
err = errors.Append(err, op1())
err = errors.Append(err, op2())
if err != nil { ... }
支持 errors.Is ¶
if errors.Is(err, os.ErrNotExist) { ... }
遍历所有错误 ¶
if merr, ok := err.(*errors.MultiError); ok {
for _, e := range merr.Errors() { ... }
}
使用场景 ¶
- 批量操作:同时执行多个操作,收集所有错误
- 资源清理:关闭多个资源,记录所有失败
- 验证:收集所有验证错误
性能优化 ¶
- 使用 sync.Pool 复用 bytes.Buffer
- Copy-on-write 优化常见的"反复 Append 到左侧"模式
- 自动展开嵌套的 MultiError
Index ¶
- func Append(left error, right error) error
- func As(err error, target any) bool
- func Cause(err error) error
- func Chain(fns ...func() error) error
- func Errorf(format string, args ...any) error
- func In(err error, targets ...error) bool
- func Is(err, target error) bool
- func IsBizError(err error) bool
- func New(msg string) error
- func Unwrap(err error) error
- func Wrap(err error, msg string, kv ...any) error
- type BizError
- func AsBizError(err error) (*BizError, bool)
- func NewBadRequestError(msg string) *BizError
- func NewBizError(code int, msg string) *BizError
- func NewBizErrorWithStatus(bizCode, httpCode int, msg string) *BizError
- func NewConflictError(msg string) *BizError
- func NewForbiddenError(msg string) *BizError
- func NewNotFoundError(msg string) *BizError
- func NewUnauthorizedError(msg string) *BizError
- func WrapBizError(code int, msg string, cause error) *BizError
- func WrapBizErrorWithStatus(bizCode, httpCode int, msg string, cause error) *BizError
- type MultiError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Append ¶
Append 将两个错误合并为一个。 任一为 nil 时返回另一个;都非 nil 时返回聚合后的 MultiError。 优化了常见的"反复 Append 到左侧"模式(copy-on-write)。
func Chain ¶ added in v0.3.0
Chain 顺序执行 fns,任一返回非 nil 立即停止并返回该错误; 全部成功返回 nil。适合"必须按序执行、前一步失败后续无意义"的场景 (如多阶段清理:阶段间有依赖时不能像 MultiError 那样继续执行后续步骤)。
fns := []func() error{flushBuffers, closeFile, removeLock}
if err := errors.Chain(fns...); err != nil { ... }
func Errorf ¶ added in v0.19.0
Errorf 构造带格式化的错误,支持 %w 包装(可出现多个),与 fmt.Errorf 同型。
与 Wrap 的分工:Errorf 用于「消息里带动态值」,Wrap 用于「固定消息 + kv 上下文」。 两者互补而非替代:需要「动态消息 + 包装 + kv 上下文」时,先 Errorf 再 Wrap。
相对 fmt.Errorf 的差异(都写在这里,行为可预期):
- nil-safe:%w 的实参为 nil 时**不进包装链**,消息按 %v 渲染为 "<nil>"。 fmt.Errorf 在此产出 "%!w(<nil>)" 噪声,且整条包装链被丢弃——这正是 Wrap 当初要解决的坑(见 Wrap 的注释),新原语不重蹈。
- %w 的实参不是 error 时同样按 %v 渲染、不进链(fmt.Errorf 产出 "%!w(...)")。
- 格式化结果为空串时返回 nil(与 Wrap(nil, ...) → nil 同一取向)。
- 多个 %w 时包装链是 Unwrap() []error(Go 1.20+ 多错误形态), errors.Is / errors.As 对链上每个错误都生效。
典型用法:
if err := db.Query(ctx, q); err != nil {
return errors.Errorf("load profile %s: %w", userID, err)
}
消息渲染与 fmt.Errorf 一致(%w 位置渲染被包装错误的 Error() 文本), 因此从 fmt.Errorf 迁过来时日志与告警的文案不会变。
func In ¶ added in v0.3.0
In 报告 err 是否匹配 targets 中的任意一个(errors.Is 语义, 支持 wrapped 错误链与 Is 自定义匹配)。
if errors.In(err, ErrNotFound, ErrForbidden) { ... }
func New ¶ added in v0.12.0
New 构造哨兵错误。与 stdlib errors.New 同型(errors.Is/As 可判定)。 补齐后下游的哨兵错误不再需要双 import(stdlib + oekit)—— 「同一进程只允许一套 errors 包」的类型同一性红线才可完整执行(#8)。
func Wrap ¶
Wrap 用 msg 包装 err 并返回新 err。err 为 nil 时返回 nil(不创建无意义包装)。 kv 列表作为附加上下文附加到包装消息(用于日志关联,例如 operation 名)。
跟 fmt.Errorf("...: %w", err) 的区别: Wrap 显式 nil-safe(避免 "%!w(<nil>)" 之类输出),并支持附加 kv 对。
业务场景:
if err := db.Query(...); err != nil {
return errors.Wrap(err, "query user", "user_id", uid)
}
输出: "query user: <原始 err> user_id=42"(kv 用 = 分隔拼接) 解包: errors.Is / errors.As 仍能识别原始 err(走 Unwrap)。
Types ¶
type BizError ¶
type BizError struct {
BizCode int `json:"biz_code"` // 业务码(语义标识)
HTTPCode int `json:"http_code"` // HTTP 状态码(0 = 由 StatusMapper 推导)
Message string `json:"message"` // 业务描述
Cause error `json:"-"` // 原始错误(可选)
}
BizError 是业务层错误类型,携带业务码(BizCode)和 HTTP 状态码(HTTPCode)。 在 service 层返回此错误后,handler 层可通过 errors.As 提取 code 和 message。
字段语义(v0.17.0 起分离):
- BizCode:业务语义标识,写入响应 body 的 code 字段(如 1001、40404)
- HTTPCode:HTTP 状态码;为 0 时由 middleware.StatusMapper 从 BizCode 推导
用法:
return nil, errors.NewNotFoundError("项目不存在")
return nil, errors.NewBadRequestError("keyword 不能为空")
return nil, errors.NewBizError(1001, "余额不足") // HTTPCode=0, 走 mapper
return nil, errors.NewBizErrorWithStatus(1001, 402, "余额不足") // 显式两码
func NewBadRequestError ¶
NewBadRequestError 创建 400 业务错误(请求参数错误)。
func NewBizError ¶
NewBizError 创建一个自定义业务码错误,HTTPCode 留空(0), handler 层会经 StatusMapper 从 BizCode 推导 HTTP 状态码。
适用于业务码与 HTTP 对齐的场景(如 BizCode=404 → HTTP 404), 或接受默认映射(BizCode=1001 → HTTP 400)。 需要显式分离两码时使用 NewBizErrorWithStatus。
func NewBizErrorWithStatus ¶
NewBizErrorWithStatus 创建一个显式指定 HTTP 状态码的业务错误。 适用于业务码与 HTTP 状态码需要分离的场景(如 BizCode=1001 但需返回 HTTP 402)。
func NewConflictError ¶
NewConflictError 创建 409 业务错误(资源冲突)。
func NewForbiddenError ¶
NewForbiddenError 创建 403 业务错误(无权限)。
func NewNotFoundError ¶
NewNotFoundError 创建 404 业务错误(资源不存在)。
func NewUnauthorizedError ¶
NewUnauthorizedError 创建 401 业务错误(未认证)。
func WrapBizError ¶
WrapBizError 包装原始错误为业务错误,HTTPCode 留空(0), handler 层经 StatusMapper 从 BizCode 推导。
func WrapBizErrorWithStatus ¶
WrapBizErrorWithStatus 包装原始错误为业务错误,显式指定 HTTP 状态码。
type MultiError ¶
type MultiError struct {
// contains filtered or unexported fields
}
MultiError 是聚合后的多错误类型。 实现 error、errors.Is(遍历检查)和 Errors()(获取子错误列表)。
func (*MultiError) Errors ¶
func (merr *MultiError) Errors() []error
Errors 返回所有子错误的切片。
返回值是内部切片的**防御性拷贝**,调用方对其 append/修改元素均不影响 MultiError 内部状态(也不得绕开 Append 的 copy-on-write 保护前提)。 聚合错误量通常为个位数,拷贝成本可忽略。
func (*MultiError) Is ¶
func (merr *MultiError) Is(target error) bool
Is 实现 errors.Is 接口,遍历所有子错误进行匹配。
func (*MultiError) Unwrap ¶
func (merr *MultiError) Unwrap() []error
Unwrap 支持 errors.As / errors.Is 遍历子错误(Go 1.20 多错误解包)。 没有它,聚合进 MultiError 的 BizError 无法被 errors.As 识别, mw.Fail 会把本应 404 的错误降级为 500。