英文:
Passing a struct method as an argument
问题
我不确定我是否试图超出Go允许的限制,但这是上下文:
我有一个名为Map
的类型,其中包含大量有用的成员函数,例如Interpolate
,Add
和Clear
。我还有一个名为Layered
的结构体类型,其中包含多个Map
。
type Map [][]float64
func (m Map) Interpolate(min, max float64) { ... }
func (m Map) Add(val float64) { ... }
func (m Map) Clear() { ... }
type Layered struct {
data []Map
}
我想在Layered
中添加一个成员函数,该函数接受Map
的任何成员函数作为参数,然后在所有包含的Map
上调用它。大致如下:
func (l Layered) MapCall(callMe func(Map)) {
for _, m := range l.data {
callMe(m)
}
}
这部分可以工作,但仅适用于Map
的不带额外参数的成员函数,例如Clear
。是否有可能接受Map
的任何成员函数作为参数(以及以...interface{}
形式的潜在参数),然后在Layered
的所有成员Map
上调用该函数,带有其正确的参数?例如,像这样:
func (l Layered) MapCall(callMe func(Map, ...interface{}), params ...interface{}) {
for _, m := range l.data {
callMe(m, params...)
}
}
英文:
I am not sure if I'm trying to exceed the limits of what Go will allow, but here is the context:
I have type called Map
with a hefty number of helpful member functions, such as Interpolate
, Add
, and Clear
. I also have a struct type, Layered
, that contains several Map
s.
type Map [][]float64
func (m Map) Interpolate(min, max float64) { ... }
func (m Map) Add(val float64) { ... }
func (m Map) Clear() { ... }
type Layered struct {
data []Map
}
I would like to add a member function to Layered
that accepts any member function of Map
as an argument, and then calls it on all of its contained Map
s. Something along the lines of:
func (l Layered) MapCall(callMe func(Map)) {
for _, m := range l.data {
callMe(m)
}
}
This partially works, but only for member functions of Map
that take no additional arguments, such as Clear
. Is it at all possible to accept any member function of Map
as an argument (along with its potential parameters in the form of an ...interface{}
), and then call the function, with its correct parameters, on all of the member Map
s in a Layered
? Something like this, for example:
func (l Layered) MapCall(callMe func(Map, ...interface{}), params ...interface{}) {
for _, m := range l.data {
callMe(m, params...)
}
}
答案1
得分: 1
你可能希望更注重功能性,而不是尝试使用接口。
我将使用你的Interpolate
方法提供一个示例。
你可以首先定义一个用于生成操作的辅助函数:
func InterpolateOp(min, max float64) func(Map) {
return func(m Map) {
m.Interpolate(min, max)
}
}
另一个更适合你的MapCall
函数的名称是MapInterpolate
。
然后,在使用MapCall
或创建操作列表时,你可以继续使用之前使用的相同类型,即func(Map)
:
var l Layered
...
l.MapCall(InterpolateOp(2, 4))
这个解决方案的关键是数据绑定到组成函数的闭包中,从而解决了最初的问题:没有足够的数据来调用适当的函数。
在你的情况下,如果有很多方法,这样做可能不值得,那么你可以考虑代码生成,因为它是重复且简单的。这超出了本问题的范围。
另请参阅:https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions
英文:
You may want to be more functional than try to use interfaces.
I will provide an example using your Interpolate
method.
You can start by defining a helper function for generating the operation:
func InterpolateOp(min, max float64) func(Map) {
return func(m Map) {
m.Interpolate(min, max)
}
}
Another name that would match your MapCall
function better is MapInterpolate
.
Then, when using MapCall
or creating lists of operations, you can use the same type you were using previously, namely func(Map)
:
var l Layered
...
l.MapCall(InterpolateOp(2, 4))
The key to this solution is that the data is bound to the closure that makes up the function, which solves the original problem: not enough data to call the appropriate functions.
In your case, if there are so many methods that this is not worth doing, then you may look into code generation, since it is repetitive and easy. That is outside the scope of this question.
See also: https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论