2

在 Go 中,您可以将函数作为参数传递,例如callFunction(fn func). 例如:

package main

import "fmt"

func example() {
    fmt.Println("hello from example")
}

func callFunction(fn func) {
    fn()
}    

func main() {
    callFunction(example)
}

但是当它是结构的成员时可以调用函数吗?以下代码将失败,但为您提供了我正在谈论的示例:

package main

import "fmt"

type Example struct {
    x int
    y int
}

var example Example

func (e Example) StructFunction() {
    fmt.Println("hello from example")
}

func callFunction(fn func) {
    fn()
}    

func main() {
    callFunction(example.StructFunction)
}

(我知道我在那个例子中试图做的有点奇怪。我遇到的确切问题并没有很好地缩小到一个简单的例子,但这是我问题的本质。但是我也很感兴趣这是从学术角度来看的)

4

4 回答 4

8

方法(不是“结构的成员”,而是任何命名类型的方法,不仅是结构)是第一类值。Go 1.0.3 尚未实现方法值,但提示版本(如即将到来的 Go 1.1 中)支持方法值。在这里引用完整的部分:

方法值

如果表达式x具有静态类型T并且M在 type 的方法集中Tx.M则称为方法值。方法值x.M是一个函数值,可以使用与 的方法调用相同的参数进行调用x.M。表达式x在方法值的求值过程中求值并保存;然后将保存的副本用作任何调用中的接收者,这可能会在以后执行。

该类型T可以是接口或非接口类型。

正如上面对方法表达式的讨论,考虑一个结构类型,它T有两个方法,Mv,其接收者是类型T,和Mp,其接收者是类型*T

type T struct {
    a int
}

func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

var t T
var pt *T
func makeT() T

表达方式

t.Mv

产生类型的函数值

func(int) int

这两个调用是等价的:

t.Mv(7)
f := t.Mv; f(7)

同样,表达式

pt.Mp

产生类型的函数值

func(float32) float32

与选择器一样,使用指针对具有值接收器的非接口方法的引用将自动取消引用该指针:pt.Mv等价于(*pt).Mv.

与方法调用一样,使用可寻址值的指针接收器对非接口方法的引用将自动获取该值的地址:t.Mv等效于(&t).Mv.

f := t.Mv; f(7)   // like t.Mv(7)
f := pt.Mp; f(7)  // like pt.Mp(7)
f := pt.Mv; f(7)  // like (*pt).Mv(7)
f := t.Mp; f(7)   // like (&t).Mp(7)
f := makeT().Mp   // invalid: result of makeT() is not addressable

尽管上面的示例使用了非接口类型,但从接口类型的值创建方法值也是合法的。

var i interface { M(int) } = myVal
f := i.M; f(7)  // like i.M(7)
于 2013-04-09T13:21:34.840 回答
2

Go 1.0 不支持使用绑定方法作为函数值。Go 1.1 将支持它,但在那之前你可以通过闭包获得类似的行为。例如:

func main() {
    callFunction(func() { example.StructFunction() })
}

这不是很方便,因为您最终会复制函数原型,但应该可以解决问题。

于 2013-04-11T05:57:50.817 回答
1

我修复了你的编译错误。

package main

import "fmt"

type Example struct {
    x, y float64
}

var example Example

func (e Example) StructFunction() {
    fmt.Println("hello from example")
}

func callFunction(fn func()) {
    fn()
}

func main() {
    callFunction(example.StructFunction)
}

输出:

hello from example
于 2013-04-09T13:23:22.373 回答
0

添加到@zzzz 很好的答案(以及在https://golang.org/ref/spec#Method_values给出的答案)这里是一个从接口类型的值创建方法值的示例。

package main

import "fmt"

type T struct{}

func (T) M(i int) { fmt.Println(i) }

func main() {
    myVal := T{}
    var i interface{ M(int) } = myVal
    f := i.M
    f(7) // like i.M(7)
}
于 2020-04-14T09:03:53.843 回答