I have a code which is similar to the following
package main
import "fmt"
func PrintThis(arg string) {
fmt.Printf("I'm printing %s", arg)
}
func PrintThisAndThat(arg1, arg2 string) {
fmt.Printf("Now printing %s and %s", arg1, arg2)
}
func Invoke(fn interface{}, args ...string) {
//fn(args...)
}
func main() {
Invoke(PrintThis, "foo")
Invoke(PrintThisAndThat, "foo", "bar")
}
This is not the actual production code, but this is a simplified version.
Question :- If I uncomment the line //fn(args...)
I get a compile error prog.go:14: cannot call non-function fn (type interface {})
How do I execute the function which is received as the argument tho the Invoke() function?
What is the right way to achieve this?
You use the Call
or CallSlice
methods of the reflect.Value
to call it as a function. As with all reflect.Value
methods, this panics is fn
is the wrong type.
func Invoke(fn interface{}, args ...string) {
v := reflect.ValueOf(fn)
rargs := make([]reflect.Value, len(args))
for i, a := range args {
rargs[i] = reflect.ValueOf(a)
}
v.Call(rargs)
}
http://play.golang.org/p/xGmNLDcLL_
You can use a type switch like so http://play.golang.org/p/opotbIGdrA
package main
import "fmt"
func PrintThis(arg string) {
fmt.Printf("I'm printing %s", arg)
}
func PrintThisAndThat(arg1, arg2 string) {
fmt.Printf("Now printing %s and %s", arg1, arg2)
}
func Invoke(fn interface{}, args ...string) {
switch m := fn.(type) {
case func(string):
m(args[0])
case func(string, string):
m(args[0], args[1])
default:
}
}
func main() {
Invoke(PrintThis, "foo")
Invoke(PrintThisAndThat, "foo", "bar")
}
But you kind of need to know what functions will be passed to make this work properly.
Btw you can turn PrintThis
into a variadic function by using ...string
instead of multiple string arguments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With