猿问

如何检查函数的返回值是否满足错误接口

我想编写一些代码来检查结构的方法并对它们做出某些断言,例如,它们返回的最后一个东西应该是error. 我尝试了以下示例脚本:


import (

    "context"

    "reflect"

)


type Service struct {

    name string

}


func (svc *Service) Handle(ctx context.Context) (string, error) {

    return svc.name, nil

}


func main() {

    s := &Service{}

    t := reflect.TypeOf(s)


    for i := 0; i < t.NumMethod(); i++ {

        f := t.Method(i).Func.Type()


        f.Out(f.NumOut() - 1).Implements(reflect.TypeOf(error))

    }

}

然而,这会产生一个


./main.go:23:51: type error is not an expression

编译的是最后的以下两行:


    var err error

    f.Out(f.NumOut() - 1).Implements(reflect.TypeOf(err))

但是,这会产生恐慌:


panic: reflect: nil type passed to Type.Implements

检查最后一个参数是否实现error接口的正确方法是什么?换句话说,我如何获得reflect.Type一个error接口?


白衣染霜花
浏览 106回答 3
3回答

神不在的星期二

如果最后一个返回值“应该是”并且error不使用Implements,这还不够,x实现e 与 x是e 不同。只需检查类型的名称和包路径。对于预先声明的类型,包括error,包路径是一个空字符串。实现的非错误类型error。type Service struct {&nbsp; &nbsp; name string}type sometype struct {}func (sometype) Error() string { return "" }func (svc *Service) Handle(ctx context.Context) (string, sometype) {&nbsp; &nbsp; return svc.name, sometype{}}func main() {&nbsp; &nbsp; s := &Service{}&nbsp; &nbsp; t := reflect.TypeOf(s)&nbsp; &nbsp; for i := 0; i < t.NumMethod(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; f := t.Method(i).Func.Type()&nbsp; &nbsp; &nbsp; &nbsp; rt := f.Out(f.NumOut() - 1)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")&nbsp; &nbsp; }}这输出:implements error? trueis error? false一个本地声明的类型,名为error不实现内置的error。type Service struct {&nbsp; &nbsp; name string}type error interface { Abc() }func (svc *Service) Handle(ctx context.Context) (string, error) {&nbsp; &nbsp; return svc.name, nil}type builtin_error interface { Error() string }func main() {&nbsp; &nbsp; s := &Service{}&nbsp; &nbsp; t := reflect.TypeOf(s)&nbsp; &nbsp; for i := 0; i < t.NumMethod(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; f := t.Method(i).Func.Type()&nbsp; &nbsp; &nbsp; &nbsp; rt := f.Out(f.NumOut() - 1)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*builtin_error)(nil)).Elem()))&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")&nbsp; &nbsp; }}这输出:implements error? falseis error? false实际的内置error.type Service struct {&nbsp; &nbsp; name string}func (svc *Service) Handle(ctx context.Context) (string, error) {&nbsp; &nbsp; return svc.name, nil}func main() {&nbsp; &nbsp; s := &Service{}&nbsp; &nbsp; t := reflect.TypeOf(s)&nbsp; &nbsp; for i := 0; i < t.NumMethod(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; f := t.Method(i).Func.Type()&nbsp; &nbsp; &nbsp; &nbsp; rt := f.Out(f.NumOut() - 1)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")&nbsp; &nbsp; }}这输出:implements error? trueis error? true

千巷猫影

使用指向接口的指针,并获取Elem它,如下所示:f.Out(f.NumOut()&nbsp;-&nbsp;1).Implements(reflect.TypeOf((*error)(nil)).Elem())

慕莱坞森

要在不使用现有错误的情况下获得reflect.TypeOfof an&nbsp;error,您可以使用以下单行代码:reflect.TypeOf((*error)(nil)).Elem()基本上,它首先获取指向 error(&nbsp;*error) 的指针的类型,然后Elem()将 TypeOf“引用”到 的类型error。
随时随地看视频慕课网APP

相关分类

Go
我要回答