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
相关产品推荐
相关产品推荐

