1. 程式人生 > >Golang反射呼叫函式

Golang反射呼叫函式

首先,來看看這段 PHP 程式碼:

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

它會輸出:

view source print ?
1 [email protected]:~/Desktop$ phpfoobar.php
2 HelloGolang
3 HelloGolang

用這個方法呼叫匹配名字的函式,非常有效。


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


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


在 Golang 中,你不能這樣做:

view source print ?
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 中:

view source print ?
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”的包。

view source print ?
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