这是一个函数和参数的后续问题。
给定以下接口变量。
var args interface{}
假设它包含以下字节:
[[74 111 104 110] [32 97 110 100 32 74 97 110 101]]
即。两个字符串" John"和Jane
和通过MethodByName获得的函数值
f := reflect.ValueOf(s.functions).MethodByName("Hello")
if f.IsValid() {
val := reflect.ValueOf(args)
// Do some kind of conversion...
result := f.Call(val) // This won't compile. Wrong type. How do I massage args of type interface{} into what's expected by the call.
}
我不特别关心它是否失败。我将通过恢复捕获电话的故障。
这里有更多细节:
var req struct {
Ver int
MsgID int
FuncName string
Args interface{}
}
dec := codec.NewDecoder(frame, s.h)
err = dec.Decode(&req)
if err != nil {
s.log.Println(err)
break
}
fmt.Println("New Msg:")
fmt.Printf(" ver : %dn", req.Ver)
fmt.Printf(" id : %dn", req.MsgID)
fmt.Printf(" func : %sn", req.FuncName)
f := reflect.ValueOf(s.functions).MethodByName(req.FuncName)
if f.IsValid() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Function is: ", req.FuncName)
var callArgs []reflect.Value
args := reflect.ValueOf(req.Args)
t := f.Type()
for i := 0; i < t.NumIn(); i++ {
t := t.In(i)
v := reflect.New(t).Elem()
if i < args.Len() {
// Convert arg to type of v and set.
arg := args.Index(i)
switch t.Kind() {
case reflect.String:
v.SetString(string(reflect.Value.Bytes(arg)))
case reflect.Slice:
if t.Elem() == reflect.TypeOf(byte(0)) {
v.SetBytes(reflect.Value.Bytes(arg))
} else {
panic("not supported")
}
case reflect.Int:
//i, err := strconv.ParseInt(string(arg), 10, 0)
// if err != nil {
// panic("bad int")
// }
// v.SetInt(i)
default:
panic("not supported")
}
}
// Collect arguments for the call below.
callArgs = append(callArgs, v)
}
result := f.Call(callArgs)
fmt.Println(result)
val := reflect.ValueOf(req.Args)
a := []reflect.Value{val}
r := f.Call(a)
fmt.Println("Returned", r[0], r[1])
}
输出:
新味精: VER:2 ID:1 功能:你好功能是:你好在f反射中恢复:接口值
上的call of call of Reflect.value.bytes注意:这是RPC API。我有一个函数名称(请参阅问题的链接)和一些作为数组传递的参数。我的示例中的参数是字符串,但您可以将任何可以传递给函数的任何事情。这是功能所需的一切。这是通用的。
例如。
你好(名称...字符串)字符串
或
add(n ... int)int
或
dosomething(a string,b int,c bool)
etc
即。我正在解除论点,但我不知道它们是什么。除了我确实知道它们会被转移到一个切片中扔进具有interface{}
类型的变量args,我希望这是有道理的
尝试以下内容。
基本思想是创建一个[]反射。通过对函数参数进行循环循环来反映呼叫的值。对于每个参数,将传入参数类型转换为函数调用中预期的类型。
var req = struct {
Ver int
MsgID int
FuncName string
Args interface{}
}{
Args: []interface{}{[]byte("John"), "Jane", 123, "456"},
}
args := req.Args.([]interface{})
var funcs Funcs
f := reflect.ValueOf(funcs).MethodByName("Hello")
var callArgs []reflect.Value
t := f.Type()
// For each function argument ...
for i := 0; i < t.NumIn(); i++ {
t := t.In(i)
v := reflect.New(t).Elem()
if i < len(args) {
// Convert arg to type of v and set.
arg := args[i]
switch t.Kind() {
case reflect.String:
switch arg := arg.(type) {
case string:
v.SetString(arg)
case []byte:
v.SetString(string(arg))
default:
panic("not supported")
}
case reflect.Slice:
if t.Elem() != reflect.TypeOf(byte(0)) {
panic("not supported")
}
switch arg := arg.(type) {
case string:
v.SetBytes([]byte(arg))
case []byte:
v.SetBytes(arg)
default:
panic("not supported")
}
case reflect.Int:
switch arg := arg.(type) {
case int:
v.SetInt(int64(arg))
case string:
i, err := strconv.ParseInt(arg, 10, 0)
if err != nil {
panic("bad int")
}
v.SetInt(i)
default:
panic("not supported")
}
default:
panic("not supported")
}
}
// Collect arguments for the call below.
callArgs = append(callArgs, v)
}
result := f.Call(callArgs)
fmt.Println(result)
该片段包括字符串,[]字节和int类型的转换。可以添加其他类型的转换。
游乐场示例
我错了 - 问题是使用 []
而不是单数值:
val := reflect.ValueOf(args)
// Do some kind of conversion...
a := []reflect.Value{val}
result := f.Call(a)
https://play.golang.org/p/aqqama-ljv