Manu Viswam
Manu Viswam

Reputation: 1646

Invoke a function which is received as an interface variable in golang

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

Answers (3)

Mr_Pink
Mr_Pink

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

Datsik
Datsik

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

cd1
cd1

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

Related Questions