将结构方法作为参数传递

Passing a struct method as an argument

我不确定我是否试图超出 Go 允许的限制,但这是上下文: 我有一个名为 Map 的类型,其中包含大量有用的成员函数,例如 InterpolateAddClear。我还有一个结构类型 Layered,它包含几个 Maps.

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。是否完全可以接受 Mapany 成员函数作为参数(连同它的 ...interface{} 形式的潜在参数),然后调用Layered 中所有成员 Map 的函数及其正确的参数?像这样的东西,例如:

func (l Layered) MapCall(callMe func(Map, ...interface{}), params ...interface{}) {
    for _, m := range l.data {
        callMe(m, params...)
    }
}

与尝试使用界面相比,您可能想要更多的功能。

我将使用您的 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