2013-04-09 138 views
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) 
} 

(我知道我想在这例子做的是一个有点古怪的具体问题,我已经没有按虽然我不是一个简单的例子,但是这是我的问题的本质,但我从学术角度也对此感兴趣)

回答

8

方法(它不是“结构的成员”但任何命名类型的方法,不仅是结构体)都是一流的值。 Go 1.0.3还没有实现方法值,但最新版本(如在Go 1.1中)支持method values。此处引述的全部部分:

的方法值

如果表达式x具有静态类型TMT类型的方法集,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 

表达

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

我修正了你的编译错误。

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 
+0

我没有试图编译该代码,它是我直接编码到SO中的问题的模拟。所以,软件包/程序和x/y类型的错误只是缺乏头脑,而不是我原来的代码问题。 我很疑惑你是如何得到输出的,因为你的代码的失败方式与我的做法一样:'method example.StructFunction不是一个表达式,必须调用'[编辑] ahh问题是Go的版本我正在运行(1.0.3)不支持它。提示确实。 – laumars 2013-04-09 13:57:11

+0

'$ go version' 'go version devel + 1a196137ed09 Tue Apr 09 18:17:55 2013 +1000 linux/amd64'这是否意味着Go现在可以做你想做的事了? – peterSO 2013-04-09 14:14:29

+0

还没有,但是当1.1推出我的回购,那么它会。鉴于这一周只有几个星期,我很乐意等待。 – laumars 2013-04-09 14:26:56

2

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

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

它不是很方便,因为你最终复制函数原型,但应该做的伎俩。