使用函数名称作为参数

时间:2013-04-09 13:13:45

标签: 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)
}

但是当它是结构的成员时,是否可以调用函数?以下代码会失败,但会给出一个我正在谈论的例子:

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 个答案:

答案 0 :(得分:8)

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

  

方法值

     

如果表达式x具有静态类型TM位于类型T的方法集中,则x.M称为方法值。方法值x.M是一个函数值,可以使用与x.M的方法调用相同的参数进行调用。在评估方法值期间评估并保存表达式x;然后将保存的副本用作任何调用中的接收器,这可以在以后执行。

     

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

     

在上面对方法表达式的讨论中,考虑一个结构类型T,它有两个方法Mv,其接收方类型为TMp,其中接收器的类型为*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)

答案 1 :(得分:2)

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

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

这不太方便,因为你最终复制了函数原型,但是应该这样做。

答案 2 :(得分: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

答案 3 :(得分:0)

要向@zzzz添加一个很好的答案(以及在https://golang.org/ref/spec#Method_values处给出的答案),下面是一个示例,该示例根据接口类型的值创建方法值。

Promise.all()