为何仅在测试代码中出现“errors.As第二个参数不应为*error”编译错误?
Go中errors.As在测试与main函数中表现差异的原因
测试代码编译报错场景
以下测试代码运行时会触发编译错误:
import ( "errors" "fmt" "testing" ) func TestError(t *testing.T) { err := &MyError{} var target error fmt.Println(errors.As(err, &target)) } type MyError struct{} func (err *MyError) Error() string { return "oops!" }
错误提示:second argument to errors.As should not be *error
main函数正常运行场景
将完全相同的逻辑放在main函数中,程序可正常执行:
package main import ( "errors" "fmt" ) func main() { err := &MyError{} var target error fmt.Println(errors.As(err, &target)) } type MyError struct{} func (err *MyError) Error() string { return "oops!" }
我在Go 1.20版本的Playground和本地开发环境中都复现了该现象,这是Go的Bug吗?
绕过测试编译错误的方法
可以通过自定义Error类型来绕过这个检查:
package main import ( "errors" "fmt" "testing" ) type Error error // 新增自定义Error类型 func TestError(t *testing.T) { err := &MyError{} var target Error // 使用自定义类型 fmt.Println(errors.As(err, &target)) } type MyError struct{} func (err *MyError) Error() string { return "oops!" }
本质原因:这不是Go的Bug
出现差异的核心原因是测试函数会自动执行vet代码检查工具,而main函数默认不会触发该检查。
vet工具会检测errors.As的参数合理性:errors.As的设计目的是将错误断言转换为具体的错误类型,直接传入*error没有实际意义——如果只是要将错误赋值给另一个error变量,直接赋值即可,完全不需要调用errors.As。
自定义type Error error后,*Error与原生*error属于不同类型,vet不会再触发这个检查,因此可以绕过,但这种写法并不符合errors.As的设计初衷。正确的用法应该是传入具体错误类型的指针,比如:
var target *MyError fmt.Println(errors.As(err, &target))
内容的提问来源于stack exchange,提问作者Sam Herrmann
相关产品推荐
相关产品推荐

