17370845950

Golang如何自定义错误类型_创建自定义error并返回方法
不能直接用 errors.New 或 fmt.Errorf,因为它们返回的 *errors.errorString 无额外字段、无法携带上下文、不支持类型断言;应定义结构体实现 error 接口,并添加导出字段和辅助方法。

为什么不能直接用 errors.Newfmt.Errorf

因为它们返回的是 *errors.errorString,没有额外字段、无法携带上下文(如错误码、请求ID、时间戳)、也不支持类型断言判断错误种类。比如你希望区分是数据库超时还是连接拒绝,仅靠错误消息字符串匹配脆弱且低效。

如何定义带字段的自定义 error 类型?

用结构体实现 error 接口(即实现 Error() string 方法),并按需添加字段。注意:结构体字段应导出(首字母大写)才能被外部访问,但 Error() 方法返回的字符串不应暴露敏感信息。

type DatabaseError struct {
    Code    int
    Message string
    ReqID   string
}

func (e *DatabaseError) Error() string {
    return e.Message
}

func (e *DatabaseError) ErrorCode() int {
    return e.Code
}
  • 必须实现 Error() string 才算满足 error 接口
  • 额外方法(如 ErrorCode())用于类型安全地提取信息
  • 建议用指针接收者,避免值拷贝;若结构体含大字段或需修改状态,这点更关键

如何在函数中返回自定义 error 并做类型判断?

返回时用 &DatabaseError{...} 构造指针;调用方用 errors.As 或类型断言识别具体类型,比字符串匹配可靠得多。

func QueryUser(id int) (string, error) {
    if id <= 0 {
        return "", &DatabaseError{
            Code:    4001,
            Message: "invalid user id",
            ReqID:   "req-abc123",
        }
    }
    return "alice", nil
}

// 调用方
name, err := QueryUser(-1)
if err != nil {
    var dbErr *DatabaseError
    if errors.As(err, &dbErr) {
        log.Printf("DB error %d for req %s", dbErr.Code, dbErr.ReqID)
    }
}
  • errors.As 是 Go 1.13+ 推荐方式,能正确处理嵌套错误(如 fmt.Errorf("wrap: %w", err)
  • 直接类型断言 err.(*DatabaseError) 仅适用于最外层错误,不推荐用于生产环境
  • 不要在 Error() 方法里拼接所有字段(如包含 ReqID),否则日志里会泄露敏感上下文

要不要嵌入 Unwrap() 支持错误链?

要。如果自定义 error 可能包装其他 error(比如重试失败后追加原因),就必须实现 Unwrap() error,否则 errors.Is/As 无法穿透到原始错误。

type WrappedError struct {
    Msg  string
    Err  error // 原始错误
    Code int
}

func (e *WrappedError) Error() string { return e.Msg }
func (e *WrappedError) Unwr

ap() error { return e.Err } func (e *WrappedError) ErrorCode() int { return e.Code }
  • 只要结构体字段含 error 类型且实现了 Unwrap()errors 包就能递归展开
  • 多个 Unwrap() 返回非 nil 时,errors.As 会按顺序尝试匹配,所以别乱返回
  • 没实现 Unwrap() 的自定义 error 在被 %w 包装后,会被当成普通字符串,丢失底层错误类型
自定义 error 的核心不是“看起来高级”,而是让调用方能安全、稳定、低成本地响应不同错误分支——字段设计是否合理、Unwrap() 是否到位、是否过度暴露内部细节,这三点比语法正确性更容易出问题。