贝利信息

如何使用Golang errors Is判断错误类型_Golang错误比较与判断方法

日期:2026-01-14 00:00 / 作者:P粉602998670
errors.Is不能判断自定义错误底层类型,因其仅通过调用错误链中各错误的Is方法判断语义相等,不进行类型断言或反射;若自定义错误未实现Is方法,则errors.Is恒返回false。

errors.Is 为什么不能判断自定义错误的底层类型

errors.Is 只检查错误链中是否存在「语义相等」的错误,即调用 Is(error) 方法返回 true 的错误。它不关心底层结构体类型,也不做类型断言或反射比对。

常见误解是以为 errors.Is(err, myErr) 能识别你定义的 *MyError 类型 —— 实际上,除非你显式实现了 Is 方法并让它返回 true,否则它永远返回 false

什么时候该用 errors.As 而不是 errors.Is

当你需要获取错误的具体值(比如访问字段、调用方法),而不是只判断「是否等于某个哨兵错误」时,errors.As 是唯一选择。

例如:你定义了带状态码和消息的错误类型 *HTTPError,想取出它的 Code 字段 —— 这必须用 errors.As 提取指针,errors.Is 完全无能为力。

var httpErr *HTTPError
if errors.As(err, &httpErr) {
    log.Printf("HTTP error code: %d", httpErr.Code)
}

自定义错误实现 Is 方法的最小必要写法

要让自己的错误能被 errors.Is 正确识别,必须在错误类型上实现 Is(target error) bool 方法,并确保逻辑可传递、无环、不依赖地址比较。

type MyError struct {
    Code int
    Msg  string
}

func (e *MyError) Error() string { return e.Msg }
func (e *MyError) Is(target error) bool {
    var t *MyError
    if errors.As(target, &t) {
        return e.Code == t.Code
    }
    return false
}

errors.Is 在多层包装下的行为边界

errors.Is 会沿着 %w 包装链逐层调用 Unwrap(),直到遇到 nil 或某层返回 true。但它不会进入非标准包装(如自定义 WrappedError 但没实现 Unwrap)。

真正容易被忽略的是:即使你用了 %w,如果被包装的错误本身不支持 Is(比如纯字符串错误),那整条链对 errors.Is 来说仍是“不可识别”的 —— 它不会自动比对错误消息字符串。