Function call by name in Golang
mikespook · · 2781 次点击 · · 开始浏览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!
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
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!