2017-10-06 124 views
2

我正在進行反射函數調用,但我目前一直試圖獲取返回值。Golang獲得反射調用的結果

示例代碼:

func (c *Client) Send(funcName protoFunction, data interface{}) (interface{}, error) { 
    funcList := c.GetProtoFuncList() 
    ctx := context.Background() 
    f := reflect.ValueOf(funcList[funcName.String()]) 
    vals := make([]reflect.Value, 2) 
    vals[0] = reflect.ValueOf(ctx) 
    vals[1] = reflect.ValueOf(data) 
    value := f.Call(vals) 
    log.Debug(value) 
    return nil, nil 
} 

我如何從「價值」的返回值和返回正確呢?

乾杯

+0

你得到它們。代碼中的'value'將是返回值的一部分。你有什麼問題? – Adrian

+0

如果您查看['Call'簽名](https://golang.org/pkg/reflect/#Value.Call),您的'value'是'[] reflect.Value'。你甚至可以打印出來。究竟是什麼問題? – JimB

+1

想知道,爲什麼你使用反射,爲什麼不直接調用它,並返回結果,例如'funcName.String()]。(func(context.Context,interface {}))(interface {},error))(ctx,data)'' (只有在'funcList'中存儲不同類型的函數時才需要類型斷言;否則,您甚至可以擺脫它,並且它變爲'return funcList [funcName.String()](ctx,data)'。) – icza

回答

2

Value.Call()返回函數調用爲[]reflect.Value的返回值。您可以使用Value.Interface()方法將reflect.Value表示的值作爲interface{}的值。從那裏,您可以使用type assertion來獲取不同類型的值。

像該簡化的例子:

var funcList = map[string]interface{}{ 
    "test": func(ctx context.Context, data interface{}) (interface{}, error) { 
     return "test-result-data:" + fmt.Sprint(data), errors.New("test-error") 
    }, 
} 

func Send(funcName string, data interface{}) (interface{}, error) { 
    f := reflect.ValueOf(funcList[funcName]) 
    params := []reflect.Value{ 
     reflect.ValueOf(context.Background()), 
     reflect.ValueOf(data), 
    } 
    res := f.Call(params) 

    ret := res[0].Interface() 
    var err error 
    if v := res[1].Interface(); v != nil { 
     err = v.(error) 
    } 
    return ret, err 
} 

測試它:

result, err := Send("test", "testData") 
fmt.Println(result, err) 

輸出:

test-result-data:testData test-error 

但是,這是不必要的複雜。你並不需要使用反射來調用一個函數,你可以直接調用它,並將結果直接返回,這樣的:

func Send2(funcName string, data interface{}) (interface{}, error) { 
    return funcList[funcName].(func(context.Context, interface{}) (interface{}, error))(
     context.Background(), data, 
    ) 
} 

測試它:

result, err = Send2("test", "testData") 
fmt.Println(result, err) 

輸出是一樣的。試試Go Playground上的示例。

+0

謝謝你的明確迴應。這正是我所需要的。 – Zander17