Function call by name in Golang

mikespook · · 2176 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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 Golang
Hello 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!


有疑问加站长微信联系(非本文作者)

本文来自:mikespook 的博客

感谢作者:mikespook

查看原文:Function call by name in Golang

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2176 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传