首先,来看看这段 PHP 代码:
1 | function foobar() { |
2 | echo "Hello Golang\n" ; |
3 | } |
4 | $funcs = array ( |
5 | "foobar" => "foobar" , |
6 | "hello" => "foobar" , |
7 | ); |
8 | $funcs [ "foobar" ](); |
9 | $funcs [ "hello" ](); |
它会输出:
1 | mikespook@mikespook-laptop:~/Desktop$ phpfoobar.php |
2 | HelloGolang |
3 | HelloGolang |
用这个方法调用匹配名字的函数,非常有效。
那么,在 Golang 中是否可能用函数的名字来调用某个函数呢?
作为一个静态、编译型语言,答案是否定的……又是肯定的!
在 Golang 中,你不能这样做:
01 | func foobar(){ |
02 | //bla...bla...bla... |
03 | } |
04 | funcname := "foobar" |
05 | funcname() |
06 | 不过可以: |
07 | |
08 | func foobar(){ |
09 | //bla...bla...bla... |
10 | } |
11 | funcs :=map[string]func() { "foobar" :foobar} |
12 | funcs[ "foobar" ]() |
但这里有一个限制:这个 map 仅仅可以用原型是“func()”的没有输入参数或返回值的函数。
如果想要用这个方法实现调用不同函数原型的函数,需要用到 interface{}。
这样,就可以添加有着不同函数原型的函数到一个 map 中:
1 | func foo(){ |
2 | //bla...bla...bla... |
3 | } |
4 | func bar(a, b, c int ){ |
5 | //bla...bla...bla... |
6 | } |
7 | funcs :=map[string]interface{}{ "foo" :foo, "bar" :bar} |
那么如何调用 map 中的函数呢?像这样吗:
funcs["foo"]()
绝对不行!这无法工作!你不能直接调用存储在空接口中的函数。
反射走进我们的生活!在 Golang 中有着叫做“reflect”的包。
01 | func Call(mmap[string]interface{}, name string, params ... interface{})(result []reflect.Value, err error) { |
02 | f= reflect.ValueOf(m[name]) |
03 | if len(params) != f.Type().NumIn(){ |
04 | err= errors.New( "The number of paramsis not adapted." ) |
05 | return |
06 | } |
07 | in:= make([]reflect.Value, len(params)) |
08 | for k, param := range params { |
09 | in[k]= reflect.ValueOf(param) |
10 | } |
11 | result= f[name].Call(in) |
12 | return |
13 | } |
14 | Call(funcs, "foo" ) |
15 | Call(funcs, "bar" , 1,2, 3) |
将函数的值从空接口中反射出来,然后使用 reflect.Call 来传递参数并调用它。
没有什么是很难理解的。
[1]http://www.du52.com/text.php?id=92