You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go中errors.As错误比较异常:自定义错误判断结果为何不符?

Go自定义错误判断异常:封装的errors.As函数误判普通错误为UserError的原因

问题现象

在实现自定义错误类型UserError时,封装的As和AsV2函数错误地将普通errors.New创建的错误判定为UserError,而直接调用errors.As的IsUserError函数能得到正确结果。程序输出为:

true
true
false

原因分析

问题核心在于As/AsV2的参数设计违背了errors.As的工作逻辑,结合Go接口特性导致误判:

1. As函数的问题

func As(sourceError, targetError error) bool {
    return errors.As(sourceError, &targetError)
}
  • 传入的emptyError(*UserError类型)会被隐式转换为error接口,此时&targetError的类型是*error(指向error接口的指针)。
  • errors.As的逻辑是检查源错误能否赋值给目标指针指向的类型。这里目标是通用的error接口,所有实现error的类型(包括普通错误)都能满足,因此返回true,完全没有起到判断*UserError的作用。

2. AsV2函数的问题

func AsV2(sourceError error, targetError interface{}) bool {
    return errors.As(sourceError, &targetError)
}
  • 传入的emptyError是*UserError类型,赋值给interface{}参数后,&targetError的类型是*interface{}。
  • errors.As会检查源错误能否赋值给interface{}——所有Go值都可以赋值给空接口,因此函数返回true,同样没有实现预期的类型判断。

3. IsUserError函数为什么正确

func IsUserError(err error) bool {
    var userError *UserError
    return errors.As(err, &userError)
}
  • 这里&userError的类型是**UserError,errors.As会遍历错误链,检查是否存在可赋值给*UserError的错误类型。普通errors.New创建的错误是*errors.errorString类型,无法匹配*UserError,因此返回false,结果正确。

修正方案

如果想封装通用的错误类型判断函数,推荐使用Go 1.18+的泛型实现类型安全的封装:

func As[T error](source error) (T, bool) {
    var target T
    ok := errors.As(source, &target)
    return target, ok
}

// 调用示例
func main() {
    err := errors.New("test Error")
    _, ok := As[*UserError](err)
    fmt.Println(ok) // 输出 false
}

若使用低于1.18的Go版本,需让调用者传入指向目标错误类型的指针:

func As(source error, target interface{}) bool {
    return errors.As(source, target)
}

// 调用示例
func main() {
    err := errors.New("test Error")
    var userErr *UserError
    fmt.Println(As(err, &userErr)) // 输出 false
}

内容的提问来源于stack exchange,提问作者BornikReal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:25:03