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

六月ゝ 毕业季﹏ 提交于 2020-02-01 03:17:06

问题


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?


回答1:


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_




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/35753768/invoke-a-function-which-is-received-as-an-interface-variable-in-golang

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!