英文:
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.Value的Call或CallSlice方法将其作为函数进行调用。与所有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)
}
答案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和有两个参数的PrintThisAndThat,fn(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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论