Search code examples
gogo-reflect

Check if a method type matches a function type


Given the following example, how to check if a method matches a function signature?

package main

import (
    "fmt"
    "context"
    "reflect"
)

// signature to check
type Fn func(context.Context)

type testStruct struct {}

func (*testStruct) DoSomething(context.Context){}
func (*testStruct) DoSomethingElse([]byte){}


func main() {
    structType := reflect.TypeOf(&testStruct{})
    for i := 0; i < structType.NumMethod(); i++ {
        fmt.Println("======================")
        method := structType.Method(i)
        fmt.Println(method.Name)
        fmt.Println(method.Type.String())

        // compare method and Fn signature
    }
}

https://play.golang.org/p/rIDfp0E14ge


Solution

  • 1. Using reflect.Value.Type().ConvertibleTo

    Note the reflect.ValueOf insted of reflect.TypeOf

    package main
    
    import (
        "context"
        "fmt"
        "reflect"
    )
    
    type Fn func(context.Context)
    
    type testStruct struct{}
    
    func (*testStruct) DoSomething(context.Context)           {}
    func (*testStruct) DoSomethingElse([]byte)                {}
    func (*testStruct) DoSomethingElse2(context.Context) error { return nil }
    
    func main() {
        structType := reflect.ValueOf(&testStruct{})
        for i := 0; i < structType.NumMethod(); i++ {
            fmt.Println("======================")
            method := structType.Method(i)
    
            // compare method and Fn
            if method.Type().ConvertibleTo(reflect.TypeOf((Fn)(nil))) {
                fmt.Println("function of correct type")
            }
        }
    }
    
    

    https://play.golang.org/p/A9_bpURinad

    2. Checking inputs and outputs individually

    package main
    
    import (
        "context"
        "fmt"
        "reflect"
    )
    
    type Fn func(context.Context)
    
    type testStruct struct{}
    
    func (*testStruct) DoSomething(context.Context) {}
    func (*testStruct) DoSomethingElse([]byte)      {}
    
    func main() {
        structType := reflect.TypeOf(&testStruct{})
        rctx := reflect.TypeOf(new(context.Context)).Elem()
        for i := 0; i < structType.NumMethod(); i++ {
            fmt.Println("======================")
            method := structType.Method(i)
            fmt.Println(method.Name)
            fmt.Println(method.Type.String())
    
            if method.Type.NumIn() != 2 {
                fmt.Println("wrong number of inputs, expected 1")
                continue
            }
    
            if method.Type.In(1) != rctx {
                fmt.Println("input of wrong type, expected context.Context")
                continue
            }
    
            if method.Type.NumOut() != 0 {
                fmt.Println("wrong number of outputs, expected 0")
                continue
            }
    
            fmt.Printf("%v is a function of correct type\n", method.Name)
        }
    }
    

    https://play.golang.org/p/YDsJ9MSiumF