Reputation: 1646
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?
Upvotes: 9
Views: 4722
Reputation: 109378
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_
Upvotes: 9
Reputation: 14824
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.
Upvotes: 5
Reputation: 16534
You need to declare the parameter fn
as a function, not as interface{}
. How is fn(args...)
supposed to work for PrintThis
, with one argument, and also with PrintThisAndThat
, with two arguments? You need to decide which type of function you want to receive and declare that as the parameter.
Upvotes: -1