如何检查函数的 return 值是否满足错误接口
How to check that a return value of a function satisfies the error interface
我想编写一些代码来检查结构的方法并对它们进行某些断言,例如,它们返回的最后一个东西应该是 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
接口的正确方法是什么?换句话说,如何获得 error
接口的 reflect.Type
?
使用指向接口的指针,并获取它的 Elem
,如下所示:
f.Out(f.NumOut() - 1).Implements(reflect.TypeOf((*error)(nil)).Elem())
要在不使用现有错误的情况下获取 error
的 reflect.TypeOf
,您可以使用此单行代码:
reflect.TypeOf((*error)(nil)).Elem()
基本上,它首先获取错误指针的类型 (*error
),然后 Elem()
"deferences" TypeOf 为 error
.[=17 的类型=]
如果最后一个return值"should be"和error
不使用Implements
,那是不够的,ximplements e 和 x 不一样 is e.
只需检查类型的名称和包路径。对于预先声明的类型,包括 error
,包路径是一个空字符串。
实现error
的非错误类型。
type Service struct {
name string
}
type sometype struct {}
func (sometype) Error() string { return "" }
func (svc *Service) Handle(ctx context.Context) (string, sometype) {
return svc.name, sometype{}
}
func main() {
s := &Service{}
t := reflect.TypeOf(s)
for i := 0; i < t.NumMethod(); i++ {
f := t.Method(i).Func.Type()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? true
is error? false
名为 error
的本地声明类型未实现内置 error
。
type Service struct {
name string
}
type error interface { Abc() }
func (svc *Service) Handle(ctx context.Context) (string, error) {
return svc.name, nil
}
type builtin_error interface { Error() string }
func main() {
s := &Service{}
t := reflect.TypeOf(s)
for i := 0; i < t.NumMethod(); i++ {
f := t.Method(i).Func.Type()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*builtin_error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? false
is error? false
实际内置 error
.
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()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? true
is error? true
我想编写一些代码来检查结构的方法并对它们进行某些断言,例如,它们返回的最后一个东西应该是 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
接口的正确方法是什么?换句话说,如何获得 error
接口的 reflect.Type
?
使用指向接口的指针,并获取它的 Elem
,如下所示:
f.Out(f.NumOut() - 1).Implements(reflect.TypeOf((*error)(nil)).Elem())
要在不使用现有错误的情况下获取 error
的 reflect.TypeOf
,您可以使用此单行代码:
reflect.TypeOf((*error)(nil)).Elem()
基本上,它首先获取错误指针的类型 (*error
),然后 Elem()
"deferences" TypeOf 为 error
.[=17 的类型=]
如果最后一个return值"should be"和error
不使用Implements
,那是不够的,ximplements e 和 x 不一样 is e.
只需检查类型的名称和包路径。对于预先声明的类型,包括 error
,包路径是一个空字符串。
实现error
的非错误类型。
type Service struct {
name string
}
type sometype struct {}
func (sometype) Error() string { return "" }
func (svc *Service) Handle(ctx context.Context) (string, sometype) {
return svc.name, sometype{}
}
func main() {
s := &Service{}
t := reflect.TypeOf(s)
for i := 0; i < t.NumMethod(); i++ {
f := t.Method(i).Func.Type()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? true
is error? false
名为 error
的本地声明类型未实现内置 error
。
type Service struct {
name string
}
type error interface { Abc() }
func (svc *Service) Handle(ctx context.Context) (string, error) {
return svc.name, nil
}
type builtin_error interface { Error() string }
func main() {
s := &Service{}
t := reflect.TypeOf(s)
for i := 0; i < t.NumMethod(); i++ {
f := t.Method(i).Func.Type()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*builtin_error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? false
is error? false
实际内置 error
.
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()
rt := f.Out(f.NumOut() - 1)
fmt.Printf("implements error? %t\n", rt.Implements(reflect.TypeOf((*error)(nil)).Elem()))
fmt.Printf("is error? %t\n", rt.Name() == "error" && rt.PkgPath() == "")
}
}
这个outputs:
implements error? true
is error? true