Golang 中的函数跟 C 的一样,是个代码块,由于golong中函数也是类型,它可以像其他类型那样赋值给一个变量。

在 Golang 中,你不能这样做:

1
2
3
4
5
func foobar() {
    // bla...bla...bla...
}
funcname := "foobar"
funcname()

不过可以:

1
2
3
4
5
func foobar() {
    // bla...bla...bla...
}
funcs := map[string]func() {"foobar":foobar}
funcs["foobar"]()

但这里有一个限制:这个 map 仅仅可以用原型是“func()”的没有输入参数或返回值的函数。

如果想要用这个方法实现调用不同函数原型的函数,需要用到 interface{}。

这样,就可以添加有着不同函数原型的函数到一个 map 中:

1
2
3
4
5
6
7
func foo() {
    // bla...bla...bla...
}
func bar(a, b, c int) {
    // bla...bla...bla...
}
funcs := map[string]interface{}{"foo":foo, "bar":bar}

那么如何调用 map 中的函数呢?像这样吗:

1
funcs["foo"]()

绝对不行!这无法工作!你不能直接调用存储在空接口中的函数。

将函数的值从空接口中反射出来,然后使用 reflect.Call 来传递参数并调用它。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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)