當(dāng)我們不希望給函數(shù)起名字的時(shí)候,可以使用匿名函數(shù),例如:func(x, y int) int { return x + y }
。
這樣的一個(gè)函數(shù)不能夠獨(dú)立存在(編譯器會返回錯誤:non-declaration statement outside function body
),但可以被賦值于某個(gè)變量,即保存函數(shù)的地址到變量中:fplus := func(x, y int) int { return x + y }
,然后通過變量名對函數(shù)進(jìn)行調(diào)用:fplus(3,4)
。
當(dāng)然,您也可以直接對匿名函數(shù)進(jìn)行調(diào)用:func(x, y int) int { return x + y } (3, 4)
。
下面是一個(gè)計(jì)算從 1 到 1 百萬整數(shù)的總和的匿名函數(shù):
func() {
sum := 0
for i := 1; i <= 1e6; i++ {
sum += i
}
}()
表示參數(shù)列表的第一對括號必須緊挨著關(guān)鍵字 func
,因?yàn)槟涿瘮?shù)沒有名稱。花括號 {}
涵蓋著函數(shù)體,最后的一對括號表示對該匿名函數(shù)的調(diào)用。
下面的例子展示了如何將匿名函數(shù)賦值給變量并對其進(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í)開發(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ù)中寫一個(gè)用于打印 Hello World
字符串的匿名函數(shù)并賦值給變量 fv
,然后調(diào)用該函數(shù)并打印變量 fv
的類型。
匿名函數(shù)像所有函數(shù)一樣可以接受或不接受參數(shù)。下面的例子展示了如何傳遞參數(shù)到匿名函數(shù)中:
func (u string) {
fmt.Println(u)
…
}(v)
請學(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
語句后發(fā)生的。
這可用于在返回語句之后修改返回的 error
時(shí)使用。
defer 語句和匿名函數(shù)
關(guān)鍵字 defer
(詳見第 6.4 節(jié))經(jīng)常配合匿名函數(shù)使用,它可以用于改變函數(shù)的命名返回值。
匿名函數(shù)還可以配合 go
關(guān)鍵字來作為 goroutine 使用(詳見第 14 章和第 16.9 節(jié))。
匿名函數(shù)同樣被稱之為閉包(函數(shù)式語言的術(shù)語):它們被允許調(diào)用定義在其它環(huán)境下的變量。閉包可使得某個(gè)函數(shù)捕捉到一些外部狀態(tài),例如:函數(shù)被創(chuàng)建時(shí)的狀態(tài)。另一種表示方式為:一個(gè)閉包繼承了函數(shù)所聲明時(shí)的作用域。這種狀態(tài)(作用域內(nèi)的變量)都被共享到閉包的環(huán)境中,因此這些變量可以在閉包中被操作,直到被銷毀,詳見第 6.9 節(jié)中的示例。閉包經(jīng)常被用作包裝函數(shù):它們會預(yù)先定義好 1 個(gè)或多個(gè)參數(shù)以用于包裝,詳見下一節(jié)中的示例。另一個(gè)不錯的應(yīng)用就是使用閉包來完成更加簡潔的錯誤檢查(詳見第 16.10.2 節(jié))。