這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
The golang’s function is a code block like C’s, but it can also be assigned to a variable as its other types.
If you are not familiar with the function, Codewalk: First-Class Functions in Go should be a good starting point for you. Already known it? Let’s go on.
First of all, look at this PHP codes:
function foobar() { echo "Hello Golang\n";}$funcs = array( "foobar" => "foobar", "hello" => "foobar",);$funcs["foobar"]();$funcs["hello"]();
It will print:
mikespook@mikespook-laptop:~/Desktop$ php foobar.php Hello GolangHello Golang
It is very useful for calling a function with name matching.
So, is it possible to call a function by its name in Golang?
As a static, compiled programming language, the answer is No … and YES!
You can not do this in Golang:
func foobar() { // bla...bla...bla...}funcname := "foobar"funcname()
You can do:
func foobar() { // bla...bla...bla...}funcs := map[string]func() {"foobar":foobar}funcs["foobar"]()
But here’s a limitation that the map only work with the prototype “func()”, no input parameters and return arguments.
If you want to call some functions have different function’s prototypes, the interface{} should be used.
Yep! interface{}, like the void pointer in C. Remember that? No? Never mind! Read this: The Go Programming Language Specification:Interface types.
Then we could add functions with different prototypes into one map:
func foo() { // bla...bla...bla...}func bar(a, b, c int) { // bla...bla...bla...}funcs := map[string]interface{}{"foo":foo, "bar":bar}
How to call a function in the map? like this?
funcs["foo"]()
NO! It does not work! You can not call a function stored in a empty interface variable directly.
Dadadada…
Reflection comes to us! It is a package called “reflect” in Golang. Do you know reflection already?
If not, just read this: 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)
Reflecting the function variable, use reflect.Call to call it and pass parameters into it at the same time.
Nothing could be hard to understand.
I’ve done a package for this functional: https://bitbucket.org/mikespook/golib/src/27c65cdf8a77/funcmap.
Hope this helps. Have a good time, gophers!