Zander17
Zander17

Reputation: 1964

Golang getting the result of a reflection call

I'm making a reflection function call but I'm currently stuck on trying to get the return values.

Example code:

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
}

How do I get the return values from "value" and return them correctly?

Cheers

Upvotes: 5

Views: 2991

Answers (1)

icza
icza

Reputation: 418585

Value.Call() returns the return values of the function call as a []reflect.Value. You may use the Value.Interface() method to get the value represented by a reflect.Value as an interface{} value. From there, you may use type assertion to obtain values of different types.

Like in this simplified example:

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
}

Testing it:

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

Output:

test-result-data:testData test-error

But this is unnecessarily complex. You don't need to use reflection to call a function, you may call it directly and return the results directly, like this:

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

Testing it:

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

Output is the same. Try the examples on the Go Playground.

Upvotes: 7

Related Questions