使用函数名称作为参数

lmo*_*org 2 methods struct types 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)
}
Run Code Online (Sandbox Code Playgroud)

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

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)
}
Run Code Online (Sandbox Code Playgroud)

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

zzz*_*zzz 8

方法(不是"结构的成员",而是任何命名类型的方法,不仅仅是结构)是第一类值.Go 1.0.3还没有实现方法值,但是tip版本(如在Go 1.1中一样)具有支持方法值.引用完整部分:

方法值

如果表达式x具有静态类型T并且M在类型的方法集中T,x.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
Run Code Online (Sandbox Code Playgroud)

表达方式

t.Mv
Run Code Online (Sandbox Code Playgroud)

产生类型的函数值

func(int) int
Run Code Online (Sandbox Code Playgroud)

这两个调用是等效的:

t.Mv(7)
f := t.Mv; f(7)
Run Code Online (Sandbox Code Playgroud)

同样,表达

pt.Mp
Run Code Online (Sandbox Code Playgroud)

产生类型的函数值

func(float32) float32
Run Code Online (Sandbox Code Playgroud)

与选择器一样,使用指针对带有值接收器的非接口方法的引用将自动取消引用该指针: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
Run Code Online (Sandbox Code Playgroud)

虽然上面的示例使用非接口类型,但从接口类型的值创建方法值也是合法的.

var i interface { M(int) } = myVal
f := i.M; f(7)  // like i.M(7)
Run Code Online (Sandbox Code Playgroud)