2013-04-09 135 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() }) 
} 

它不是很方便,因爲你最終複製函數原型,但應該做的伎倆。