當(dāng)我們不希望給函數(shù)起名字的時(shí)候,可以使用匿名函數(shù),例如:func(x, y int) int { return x + y }。
這樣的一個(gè)函數(shù)不能夠獨(dú)立存在(編譯器會(huì)返回錯(cuò)誤:non-declaration statement outside function body),但可以被賦值于某個(gè)變量,即保存函數(shù)的地址到變量中:fplus := func(x, y int) int { return x + y },然后通過(guò)變量名對(duì)函數(shù)進(jìn)行調(diào)用:fplus(3,4)。
當(dāng)然,您也可以直接對(duì)匿名函數(shù)進(jìn)行調(diào)用:func(x, y int) int { return x + y } (3, 4)。
下面是一個(gè)計(jì)算從 1 到 1 百萬(wàn)整數(shù)的總和的匿名函數(shù):
func() {
sum := 0
for i := 1; i <= 1e6; i++ {
sum += i
}
}()
表示參數(shù)列表的第一對(duì)括號(hào)必須緊挨著關(guān)鍵字 func,因?yàn)槟涿瘮?shù)沒(méi)有名稱?;ɡㄌ?hào) {} 涵蓋著函數(shù)體,最后的一對(duì)括號(hào)表示對(duì)該匿名函數(shù)的調(diào)用。
下面的例子展示了如何將匿名函數(shù)賦值給變量并對(duì)其進(jìn)行調(diào)用(function_literal.go):
package main
import "fmt"
func main() {
f()
}
func f() {
for i := 0; i < 4; i++ {
g := func(i int) { fmt.Printf("%d ", i) } //此例子中只是為了演示匿名函數(shù)可分配不同的內(nèi)存地址,在現(xiàn)實(shí)開(kāi)發(fā)中,不應(yīng)該把該部分信息放置到循環(huán)中。
g(i)
fmt.Printf(" - g is of type %T and has value %v\n", g, g)
}
}
輸出:
0 - g is of type func(int) and has value 0x681a80
1 - g is of type func(int) and has value 0x681b00
2 - g is of type func(int) and has value 0x681ac0
3 - g is of type func(int) and has value 0x681400
我們可以看到變量 g 代表的是 func(int),變量的值是一個(gè)內(nèi)存地址。
所以我們實(shí)際上擁有的是一個(gè)函數(shù)值:匿名函數(shù)可以被賦值給變量并作為值使用。
練習(xí) 6.8 在 main 函數(shù)中寫(xiě)一個(gè)用于打印 Hello World 字符串的匿名函數(shù)并賦值給變量 fv,然后調(diào)用該函數(shù)并打印變量 fv 的類型。
匿名函數(shù)像所有函數(shù)一樣可以接受或不接受參數(shù)。下面的例子展示了如何傳遞參數(shù)到匿名函數(shù)中:
func (u string) {
fmt.Println(u)
…
}(v)
請(qǐng)學(xué)習(xí)以下示例并思考(return_defer.go):函數(shù) f 返回時(shí),變量 ret 的值是什么?
package main
import "fmt"
func f() (ret int) {
defer func() {
ret++
}()
return 1
}
func main() {
fmt.Println(f())
}
變量 ret 的值為 2,因?yàn)?ret++ 是在執(zhí)行 return 1 語(yǔ)句后發(fā)生的。
這可用于在返回語(yǔ)句之后修改返回的 error 時(shí)使用。
defer 語(yǔ)句和匿名函數(shù)
關(guān)鍵字 defer (詳見(jiàn)第 6.4 節(jié))經(jīng)常配合匿名函數(shù)使用,它可以用于改變函數(shù)的命名返回值。
匿名函數(shù)還可以配合 go 關(guān)鍵字來(lái)作為 goroutine 使用(詳見(jiàn)第 14 章和第 16.9 節(jié))。
匿名函數(shù)同樣被稱之為閉包(函數(shù)式語(yǔ)言的術(shù)語(yǔ)):它們被允許調(diào)用定義在其它環(huán)境下的變量。閉包可使得某個(gè)函數(shù)捕捉到一些外部狀態(tài),例如:函數(shù)被創(chuàng)建時(shí)的狀態(tài)。另一種表示方式為:一個(gè)閉包繼承了函數(shù)所聲明時(shí)的作用域。這種狀態(tài)(作用域內(nèi)的變量)都被共享到閉包的環(huán)境中,因此這些變量可以在閉包中被操作,直到被銷(xiāo)毀,詳見(jiàn)第 6.9 節(jié)中的示例。閉包經(jīng)常被用作包裝函數(shù):它們會(huì)預(yù)先定義好 1 個(gè)或多個(gè)參數(shù)以用于包裝,詳見(jiàn)下一節(jié)中的示例。另一個(gè)不錯(cuò)的應(yīng)用就是使用閉包來(lái)完成更加簡(jiǎn)潔的錯(cuò)誤檢查(詳見(jiàn)第 16.10.2 節(jié))。