如何通过反射将一个函数声明为一个类型?

时间:2019-01-02 01:28:18

标签: function go methods reflection types

我正在Go中编写RPC服务。我不知道如何将struct方法转换为Handler函数。

我尝试过的事情:

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())
    }
}

但是失败了。我该怎么办?

1 个答案:

答案 0 :(得分:1)

方法TestService.Foo的类型为func(a int) error,与类型Handle不同(Handle具有相同的基础类型,但它是一种新的,独特的类型)。

您必须检查此确切类型:

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

进行此更改后,输出将为:

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

Go Playground上尝试。

请注意,您可以对type assertion执行相同的操作,例如:

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

Go Playground上尝试这个。

还要注意,如果您确实想使用Handle类型的定义,则可以检查函数值是否为Handle类型的变量的assignable。使用反射,此检查实质上意味着方法的类型是否可分配给Handle的类型。

它是这样的:

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

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())
}

使用类型断言(Go Playground)时:

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

使用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))
}