Methods 使用函数名作为参数

Methods 使用函数名作为参数,methods,types,struct,go,first-class-functions,Methods,Types,Struct,Go,First Class Functions,在Go中,可以将函数作为参数传递,如callFunction(fn func)。例如: package main import "fmt" func example() { fmt.Println("hello from example") } func callFunction(fn func) { fn() } func main() { callFunction(example) } func main() { callFunction(f

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

package main

import "fmt"

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

func callFunction(fn func) {
    fn()
}    

func main() {
    callFunction(example)
}
func main() {
    callFunction(func() { example.StructFunction() })
}
但是,当函数是结构的成员时,是否可以调用它?下面的代码可能会失败,但为您提供了一个我所说的示例:

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)
}
(我知道我在那个例子中试图做的有点奇怪。我的问题并没有很好地缩小到一个简单的例子,但这是我问题的本质。然而,我也从学术角度对此感兴趣)

方法(不是“结构的成员”,而是任何命名类型的方法,不仅仅是结构)是一流的价值观。Go 1.0.3尚未实现方法值,但tip版本(如即将发布的Go 1.1)支持。在此引用完整部分:

方法值

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

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

var i interface { M(int) } = myVal
f := i.M; f(7)  // like i.M(7)
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)
}

如以上方法表达式的讨论,考虑结构类型<代码>代码>代码>两种方法,<代码> MV<代码>,其接收器类型为“代码> t>代码>,<代码> MP.<代码>,其接收器类型为“代码> *T < < /P>”

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
pt.Mp
生成类型为的函数值

func(int) int
func(float32) float32
这两种调用是等效的:

t.Mv(7)
f := t.Mv; f(7)
同样,表达式

t.Mv
pt.Mp
生成类型为的函数值

func(int) int
func(float32) float32
与选择器一样,对使用指针的值接收器的非接口方法的引用将自动取消对该指针的引用:
pt.Mv
相当于
(*pt.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
与方法调用一样,对使用可寻址值的指针接收器的非接口方法的引用将自动获取该值的地址:
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)
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)
}

我修复了你的编译错误

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

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

package main

import "fmt"

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

func callFunction(fn func) {
    fn()
}    

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

这不是很方便,因为您最终复制了函数原型,但应该做到这一点。

要添加到@zzzz伟大的答案(以及在中给出的答案),这里有一个从接口类型的值创建方法值的示例

var i interface { M(int) } = myVal
f := i.M; f(7)  // like i.M(7)
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)
}

我并没有试图编译那个代码,它是我的问题的一个模型,我直接将它编码到SO中。因此,th包/程序和x/y类型的错误只是心不在焉,而不是我的原始代码的问题。我很困惑您是如何获得输出的,因为您的代码与我的代码一样失败:
method example.StructFunction不是表达式,必须调用
ahh问题是我正在运行的Go版本(1.0.3)不支持它。提示是这样的。
$go version
go version devel+1a196137ed09周二4月9日18:17:55 2013+1000 linux/amd64
这是否意味着go now可以实现您想要的功能?还没有,但当1.1推出到我的回购时,它就会实现。考虑到现在只剩下几个星期了,我很乐意等待。