在golang中,可以通过接口变量调用接收到的函数。

huangapple go评论89阅读模式
英文:

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

问题

我有一个类似以下代码的代码:

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() 函数的函数?

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

英文:

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

得分: 9

你可以使用reflect.ValueCallCallSlice方法将其作为函数进行调用。与所有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)
}

你可以在这里查看示例代码:http://play.golang.org/p/xGmNLDcLL_

英文:

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

得分: 5

你可以像这样使用类型开关:http://play.golang.org/p/opotbIGdrA

package main

import "fmt"

func PrintThis(arg string) {
    fmt.Printf("我正在打印 %s", arg)
}

func PrintThisAndThat(arg1, arg2 string) {
    fmt.Printf("现在打印 %s 和 %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")
}

但是你需要知道将要传递的函数,以使其正常工作。

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

英文:

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

得分: -1

你需要将参数fn声明为一个函数,而不是interface{}。对于只有一个参数的PrintThis和有两个参数的PrintThisAndThatfn(args...)应该如何工作?你需要决定你想要接收的函数类型,并将其声明为参数。

英文:

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.

huangapple
  • 本文由 发表于 2016年3月3日 01:09:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/35753768.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定