[email protected]:~/Desktop$ php foobar.php Hello Golang Hello Golang
用这个方法调用匹配名字的函数,非常有效。
那么,在 Golang 中是否可能用函数的名字来调用某个函数呢?
作为一个静态、编译型语言,答案是否定的……又是肯定的!
在 Golang 中,你不能这样做:
func foobar() { // bla...bla...bla... } funcname := "foobar" funcname()不过可以:
func foobar() { // bla...bla...bla... } funcs := map[string]func() {"foobar":foobar} funcs["foobar"]()但这里有一个限制:这个 map 仅仅可以用原型是“func()”的没有输入参数或返回值的函数。
如果想要用这个方法实现调用不同函数原型的函数,需要用到 interface{}。是啊!interface{},跟 C 中的 void 指针类似。还记得这个东西吗?不记得了?没事,看看这个吧:《The Go Programming Language Specification:Interface types》。
这样,就可以添加有着不同函数原型的函数到一个 map 中:
func foo() { // bla...bla...bla... } func bar(a, b, c int) { // bla...bla...bla... } funcs := map[string]interface{}{"foo":foo, "bar":bar}那么如何调用 map 中的函数呢?像这样吗:
funcs["foo"]()绝对不行!这无法工作!你不能直接调用存储在空接口中的函数。
反射走进我们的生活!在 Golang 中有着叫做“reflect”的包。你是否了解反射了呢?
如果还没有,那么阅读一下这个:《Laws of reflection》吧。哦,这里有个中文版本:《反射的规则》。func Call(m map[string]interface{}, name string, params ... interface{}) (result []reflect.Value, err error) { f = reflect.ValueOf(m[name]) if len(params) != f.Type().NumIn() { err = errors.New("The number of params is not adapted.") return } in := make([]reflect.Value, len(params)) for k, param := range params { in[k] = reflect.ValueOf(param) } result = f.Call(in) return } Call(funcs, "foo") Call(funcs, "bar", 1, 2, 3)将函数的值从空接口中反射出来,然后使用 reflect.Call 来传递参数并调用它。
没有什么是很难理解的。我已经完成了一个包来实现这个功能,在这里:https://github.com/mikespook/golib/tree/master/funcmap.
希望这有些帮助。好运,地鼠们!