简体   繁体   English

如何通过反射将 func 断言为类型?

[英]How to assert a func to a type by reflect?

I am writing an RPC service in Go.我正在用 Go 编写一个 RPC 服务。 I don't know how to convert a struct method to a Handler func.我不知道如何将 struct 方法转换为Handler func。

What I tried:我试过的:

type TestService struct{}

func (TestService) Foo(a int) error {
    return nil
}

type Handle func(a int) error

func TestHandle(t *testing.T) {
    ts := new(TestService)
    val := reflect.ValueOf(ts)
    // typ := reflect.TypeOf(ts)

    // fmt.Println(val.Method(0).Interface())
    // fmt.Println(val.Method(0).Type().ConvertibleTo(reflect.TypeOf(new(Handle))))

    switch reflect.Indirect(val).Method(0).Interface().(type) {
    case Handle:
        fmt.Println(" okokok " )
    default:
        fmt.Println(reflect.Indirect(val).Method(0).Type())
    }
}

But it fails.但它失败了。 How should I do it?我该怎么做?

The method TestService.Foo is of type func(a int) error , which is not the same as type Handle ( Handle has the same underlying type, but it is a new, distinct type).方法TestService.Foo的类型为func(a int) error ,它与类型HandleHandle具有相同的底层类型,但它是一个新的、不同的类型)。

You have to check for this exact type:你必须检查这个确切的类型:

case func(a int) error:
    fmt.Println(" okokok ")

With this change, output will be:进行此更改后,输出将为:

=== RUN   TestHandle
 okokok 
--- PASS: TestHandle (0.00s)
PASS

Try it on the Go Playground .Go Playground上试一试。

Note that you can do the same with a type assertion , eg:请注意,您可以对类型断言执行相同的操作,例如:

if _, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
    fmt.Println(" okokok ")
}

Try this one on the Go Playground .Go Playground上试试这个。

Also note that if you do want to use the Handle type definition, you could check if the function value is assignable to a variable of Handle type.另请注意,如果您确实想使用Handle类型定义,则可以检查函数值是否可分配Handle类型的变量。 Using reflection, this check essentially means if the type of the method is assignable to the type of Handle .使用反射,这种检查本质上是指方法的类型是否可分配给Handle的类型。

This is how it would look like:这是它的样子:

th := reflect.TypeOf(Handle(nil))
if reflect.Indirect(val).Method(0).Type().AssignableTo(th) {
    fmt.Println(" okokok ")
}

Try this one on the Go Playground .Go Playground上试试这个。

Obtaining the function value获取函数值

Solutions above only check if the given method is of the given function type.上面的解决方案只检查给定的方法是否属于给定的函数类型。 If you also need the function value (so you can call it), this is how you can do it:如果您还需要函数值(以便您可以调用它),您可以这样做:

When using type switch ( Go Playground ):使用类型开关( Go Playground )时:

switch hf := reflect.Indirect(val).Method(0).Interface().(type) {
case func(a int) error:
    fmt.Println(" okokok ", hf(0))
default:
    fmt.Println(reflect.Indirect(val).Method(0).Type())
}

When using type assertion ( Go Playground ):使用类型断言 ( Go Playground ) 时:

if hf, ok := reflect.Indirect(val).Method(0).Interface().(func(a int) error); ok {
    fmt.Println(" okokok ", hf(0))
}

Using Value.Convert() ( Go Playground ):使用Value.Convert() ( Go Playground ):

m := reflect.Indirect(val).Method(0)
th := reflect.TypeOf(Handle(nil))
if m.Type().AssignableTo(th) {
    var hf Handle = m.Convert(th).Interface().(Handle)
    fmt.Println(" okokok ", hf(0))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM