如何正确使用reflect包中的.Call方法

8

我很久以来一直在解决一个关于reflect包中的.Call函数的问题。

现在我正在调用如下代码:

params := "some map[string][]string"
in := make([]reflect.Value,0)
return_values := reflect.ValueOf(&controller_ref).MethodByName(action_name).Call(in)

我正在调用的方法如下:

func (c *Controller) Root(params map[string][]string) map[string] string{}

我不太明白如何操作 "in" 变量以正确地将我需要的映射传递到函数中。我看到 make() 中的第二个参数是参数的长度?但我不太明白如何格式化变量以正确地传递我的参数。我一直递归地遇到错误信息:

reflect: Call with too few input arguments

非常感谢您的帮助!

2个回答

15

根据Value.Call文档:

Call用输入参数in调用函数v。例如,如果len(in) == 3,则v.Call(in)表示Go调用v(in [0],in [1],in [2])

因此,如果您想调用仅具有一个参数的函数,则in必须包含一个正确类型的reflect.Value,在您的情况下为map[string][]string

这个表达式是:

in := make([]reflect.Value,0)

创建长度为0的切片。将其传递给Value.Call会导致你收到的恐慌,因为你需要1个参数,而不是零个。

正确的调用应该是:

m := map[string][]string{"foo": []string{"bar"}}

in := []reflect.Value{reflect.ValueOf(m)}

myMethod.Call(in)

啊,好的,我明白了,非常感谢! :) 感激你今天的帮助! - user1493543

11

该调用试图向期望一个参数的控制器传递零个参数(in是一个空切片)。你需要做的更像是 in:= []reflect.Value{reflect.ValueOf(params)}

一旦找到方法,您还可以调用.Interface(),然后使用类型断言获取一个可以直接调用的func

// get a reflect.Value for the method
methodVal := reflect.ValueOf(&controller_ref).MethodByName(action_name)
// turn that into an interface{}
methodIface := methodVal.Interface()
// turn that into a function that has the expected signature
method := methodIface.(func(map[string][]string) map[string]string)
// call the method directly
res := method(params)

那么,您甚至可以将 method 缓存到以方法名称为键的映射中,这样下次调用时就不必执行 reflect 操作。但是,这并非必须做到让代码运行。


我不理解你最后一段的意思。 - nemo
抱歉。我添加了代码。我的意思是,一旦找到该方法,获取一个 interface {},然后通过类型断言完成其余操作。 - twotwotwo
(@nemo--这样说清楚了吗?即使你可能认为这不是一个好主意?) - twotwotwo
1
+1,现在我明白了 :) 这不是一个坏主意,但你需要在编译时知道类型,这并不总是可能的。 - nemo
非常感谢您的回答。这有助于我解决自己的问题:https://dev59.com/X4bca4cB1Zd3GeqPVmsQ#27692822 - Cito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接