上个星期,我写了篇《Function call by name in Golang》。因为是英文的,因此被人诟病(说谁,谁知道!)。好吧,如今用中文从新写一遍。 php
Golang 中的函数跟 C 的同样,是个代码块,不过它能够像其余类型那样赋值给一个变量。 html
若是你对函数不熟悉,《Codewalk: First-Class Functions in Go》应该是个不错的起点。已经有所了解?那么继续吧! golang
首先,来看看这段 PHP 代码: c#
functionfoobar() {
echo"Hello Golang\n";
}
$funcs=array(
"foobar"=>"foobar",
"hello" =>"foobar",
);
$funcs["foobar"]();
$funcs["hello"]();
|
它会输出: 函数
mikespook@mikespook-laptop:~/Desktop$ php foobar.php
Hello Golang
Hello Golang
|
用这个方法调用匹配名字的函数,很是有效。 spa
那么,在 Golang 中是否可能用函数的名字来调用某个函数呢? 指针
做为一个静态、编译型语言,答案是否认的……又是确定的! code
在 Golang 中,你不能这样作: orm
func foobar() {
// bla...bla...bla...
}
funcname :="foobar"
funcname()
|
不过能够: htm
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, cint) {
// 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])
iflen(params) != f.Type().NumIn() {
err = errors.New("The number of params is not adapted.")
return
}
in := make([]reflect.Value, len(params))
fork, 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://bitbucket.org/mikespook/golib/src/27c65cdf8a77/funcmap.
但愿这有些帮助。好运,地鼠们!