1

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

CodeBreaker
  • 488
  • 9
  • 18

1 Answers1

0

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

CodeBreaker
  • 488
  • 9
  • 18
  • @mh-cbon I did and to my understanding with that I can check if `testStruct` implements some interface. In this case I want to check if struct methods have a signature `func(context.Context)`. i tried with `Implements`, didn't work. If it can be done with `Implements`, could You please put it in an answer? – CodeBreaker Jun 02 '20 at 21:04
  • 1
    OK, i found the solution. For somewhat reasons, if you browse the method of the type `reflect.TypeOf(&testStruct{})` and the value `reflect.ValueOf(&testStruct{})`, you will get different results. see https://play.golang.org/p/7NsxKbnFnfC –  Jun 02 '20 at 22:07
  • Thanks for that. I've updated the answer with your solution. – CodeBreaker Jun 03 '20 at 07:16
  • you are welcome, this is not an easy package to handle. –  Jun 03 '20 at 07:18