Golang反射呼叫函式
阿新 • • 發佈:2018-11-23
首先,來看看這段 PHP 程式碼:
view source print ?1 |
function foobar() { |
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, c int ){ |
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 |
if len(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 |
for k, 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