Reputation: 5357
I want to test a given function in runtime, to verify that it matches a certain signature. It's sufficient that this signature complies with some interface, not a specific implementation.
I can't seem to find the right pattern to do such validation. In runtime, the function's type is using the implementation.
How can I compare the function's signature to the interface?
package main
import "fmt"
type myinteface interface{
DoSomething(int) string
}
type myfunc func(myinteface)
type impl struct {}
func (im *impl) DoSomething(int) string{
return "fsdfsd"
}
func do(i interface{}) {
switch v := i.(type) {
case func(myinteface):
fmt.Print("doesn't stop here")
case func(impl):
fmt.Print("this does work")
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func test(im impl) {}
func main() {
do(test)
}
see it live in playground
Upvotes: 3
Views: 2728
Reputation: 290
From your question it is a little hard to tell what you want to assert about the function. I wrote up something that I think does what you need.
Note that the function test
in your question did not take a parameter that implements myinteface
as it was not a pointer.
As mentoined, you probably need to find a different solution to your problem you are trying to solve using this.
package main
import "fmt"
import "reflect"
type myinteface interface {
DoSomething(int) string
}
type myfunc func(myinteface)
type impl struct{}
func (im *impl) DoSomething(int) string {
return "fsdfsd"
}
//Does the function passed as `i` take a type that implements the `myinteface` type as first parameter
func do(i interface{}) {
functionType := reflect.TypeOf(i)
if functionType.Kind() != reflect.Func {
fmt.Printf("(%s) is not a function", functionType)
}
ourInterfaceType := reflect.TypeOf((*myinteface)(nil)).Elem()
if functionType.In(0).Implements(ourInterfaceType) {
fmt.Printf("(%s)'s first paramter implements the `myinteface` interface\n", functionType)
} else {
fmt.Printf("(%s)'s first paramter does not implement the `myinteface` interface\n", functionType)
}
}
func test(im *impl) {}
func test2(im impl) {}
func main() {
do(test)
do(test2)
}
Upvotes: 0
Reputation: 12875
You may check arguments type manually using reflect
package. Here's an example for myinteface
. I check whether first parameter Implements
desired interface. For brevity I suppose function has only one obligatory argument. For production it's better to check number of arguments (commented out string with NumIn()
) and all their types in a cycle.
func do(i interface{}) {
val := reflect.ValueOf(i)
typ := val.Type()
// numIn := typ.NumIn()
arg0 := typ.In(0)
modelType := reflect.TypeOf((*myinteface)(nil)).Elem()
if arg0.Implements(modelType) {
fmt.Println("OK")
} else {
fmt.Println("not OK")
}
}
Also, please pay attention to a receiver type: value or pointer. For example, here only test2
function argument implements myinteface
, but test
doesn't because of the pointer receiver on the struct impl
.
func test(im impl) {}
func test2(im *impl) {}
func main() {
do(test)
do(test2)
}
Demo: https://play.golang.org/p/ZDZKZIh2lW
If you change struct definition to value receiver then both function's arguments implement it:
type impl struct{}
func (im impl) DoSomething(int) string {
return "fsdfsd"
}
https://play.golang.org/p/xvasgBs-_a
Upvotes: 2