调用在golang中作为接口变量接收的函数

时间:2016-03-02 17:09:07

标签: generics reflection go interface

我的代码类似于以下

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")
}

这不是实际的生产代码,但这是一个简化版本。

问题: - 如果我取消注释行//fn(args...),我收到编译错误prog.go:14: cannot call non-function fn (type interface {})

如何执行Invoke()函数作为参数接收的函数?

实现这一目标的正确方法是什么?

3 个答案:

答案 0 :(得分:6)

您可以使用reflect.Value的{​​{3}}或Call方法将其称为函数。与所有reflect.Value方法一样,此恐慌是fn类型错误。

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)
}

CallSlice

答案 1 :(得分:3)

您可以使用类似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")
}

但您需要知道将传递哪些函数才能使其正常工作。

顺便说一句,您可以使用PrintThis而不是多个字符串参数将...string转换为可变参数函数。

答案 2 :(得分:0)

您需要将参数fn声明为函数,而不是interface{}fn(args...)如何适用于PrintThis,有一个参数,还有PrintThisAndThat,有两个参数?您需要确定要接收的函数类型,并将其声明为参数。