Golang反射調用函數

首先,來看看這段 PHP 代碼:

1 functionfoobar() {
2     echo"Hello Golang\n";
3 }
4 $funcs= array(
5     "foobar"=> "foobar",
6     "hello" => "foobar",
7 );
8 $funcs["foobar"]();
9 $funcs["hello"]();

它會輸出:

1 mikespook@mikespook-laptop:~/Desktop$ phpfoobar.php
2 HelloGolang
3 HelloGolang

用這個方法調用匹配名字的函數,非常有效。


那麼,在 Golang 中是否可能用函數的名字來調用某個函數呢?


作爲一個靜態、編譯型語言,答案是否定的……又是肯定的!


在 Golang 中,你不能這樣做:

01 func foobar(){
02     //bla...bla...bla...
03 }
04 funcname :="foobar"
05 funcname()
06 不過可以:
07   
08 func foobar(){
09     //bla...bla...bla...
10 }
11 funcs :=map[string]func() {"foobar":foobar}
12 funcs["foobar"]()

但這裏有一個限制:這個 map 僅僅可以用原型是“func()”的沒有輸入參數或返回值的函數。

如果想要用這個方法實現調用不同函數原型的函數,需要用到 interface{}。

這樣,就可以添加有着不同函數原型的函數到一個 map 中:

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

那麼如何調用 map 中的函數呢?像這樣嗎:


funcs["foo"]()

絕對不行!這無法工作!你不能直接調用存儲在空接口中的函數。


反射走進我們的生活!在 Golang 中有着叫做“reflect”的包。

01 func Call(mmap[string]interface{}, name string, params ... interface{})(result []reflect.Value, err error) {
02     f= reflect.ValueOf(m[name])
03     iflen(params) != f.Type().NumIn(){
04         err= errors.New("The number of paramsis not adapted.")
05         return
06     }
07     in:= make([]reflect.Value, len(params))
08     fork, param := range params {
09         in[k]= reflect.ValueOf(param)
10     }
11     result= f[name].Call(in)
12     return
13 }
14 Call(funcs,"foo")
15 Call(funcs,"bar", 1,2, 3)

將函數的值從空接口中反射出來,然後使用 reflect.Call 來傳遞參數並調用它。

沒有什麼是很難理解的。


[1]http://www.du52.com/text.php?id=92

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章