Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type switch to validate function by interface

Tags:

go

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

like image 330
Yaron Schwimmer Avatar asked Nov 26 '25 17:11

Yaron Schwimmer


1 Answers

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

like image 128
Eugene Lisitsky Avatar answered Nov 28 '25 15:11

Eugene Lisitsky



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!