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

huangapple go评论72阅读模式
英文:

How to properly use .Call in reflect package

问题

我正在使用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

非常感谢任何帮助!

英文:

Been having one last issue with my code which involves the .Call function in the reflect package.

So I'm making a call such as this:

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

where the method I'm making the .Call to is as follows:

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

What I don't quite understand is how to manipulate the "in" variable in order to properly pass the map I need to into the function. I see that the second parameter in the make() is the length of the parameter? But I don't quite understand how to format the vars in order to properly pass in my parameter. I am recursively running into the error message:

reflect: Call with too few input arguments

Any help would be much appreciated!

答案1

得分: 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)
英文:

From the Value.Call documentation:

> Call calls the function v with the input arguments in. For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).

So if you want to call a function with one parameter, in must contain one reflect.Value of the
right type, in your case map[string][]string.

The expression

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

creates a slice with length 0. Passing this to Value.Call will result in the panic you receive as you
need 1 parameter, not zero.

The correct call would be:

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

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

myMethod.Call(in)

答案2

得分: 11

调用尝试将零个参数传递给一个期望一个参数的控制器(in是一个空切片)。你需要做一些类似于in := []reflect.Value{reflect.ValueOf(params)}的操作。

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

// 获取方法的 reflect.Value
methodVal := reflect.ValueOf(&controller_ref).MethodByName(action_name)
// 将其转换为 interface{}
methodIface := methodVal.Interface()
// 将其转换为具有预期签名的函数
method := methodIface.(func(map[string][]string) map[string]string)
// 直接调用该方法
res := method(params)

(然后,你甚至可以通过以方法名称为键将method缓存到一个映射中,这样你就不必在下一次调用时进行reflect操作。但这不是必须的,它仍然可以正常工作。)

英文:

The call is trying to pass zero parameters to a controller that expects one param (in is an empty slice). You need to do something more like in := []reflect.Value{reflect.ValueOf(params)}.

You could also call .Interface() once you've found the method, then use type assertion to get a func you can call directly:

// 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)

(Then you could even cache method in a map keyed by method name, so you wouldn't have to do reflect operations next call. But you don't have to do that for it to work.)

huangapple
  • 本文由 发表于 2013年12月21日 10:57:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/20714939.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定