发表于 2018-9-20 11:12:21

Function call by name in Golang

  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 := mapfunc() {"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 := mapinterface{}{"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 mapinterface{}, name string, params ... interface{}) (result []reflect.Value, err error) {  
f = reflect.ValueOf(m)
  
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 = 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!


页: [1]
查看完整版本: Function call by name in Golang