GO語(yǔ)言的匿名函數(shù)就是閉包
基本概念
閉包是可以包含自由(未綁定到特定對(duì)象)變量的代碼塊,這些變量不在這個(gè)代碼塊內(nèi)或者任何全局上下文中定義,而是在定義代碼塊的環(huán)境中定義。要執(zhí)行的代碼塊(由于自由變量包含
在代碼塊中,所以這些自由變量以及它們引用的對(duì)象沒(méi)有被釋放)為自由變量提供綁定的計(jì)算環(huán)境(作用域)。
閉包的價(jià)值
閉包的價(jià)值在于可以作為函數(shù)對(duì)象或者匿名函數(shù),對(duì)于類(lèi)型系統(tǒng)而言,這意味著不僅要表示數(shù)據(jù)還要表示代碼。支持閉包的多數(shù)語(yǔ)言都將函數(shù)作為第一級(jí)對(duì)象,就是說(shuō)這些函數(shù)可以存儲(chǔ)到
變量中作為參數(shù)傳遞給其他函數(shù),最重要的是能夠被函數(shù)動(dòng)態(tài)創(chuàng)建和返回。
Go語(yǔ)言中的閉包
Go語(yǔ)言中的閉包同樣也會(huì)引用到函數(shù)外的變量。閉包的實(shí)現(xiàn)確保只要閉包還被使用,那么被閉包引用的變量會(huì)一直存在。例:
// closure.go
package main
import (
"fmt"
)
func main() {
var j int = 5
a := func() func() {
var i int = 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}() //末尾的括號(hào)表明匿名函數(shù)被調(diào)用,并將返回的函數(shù)指針賦給變量a
a()
j *= 2
a()
}
輸出:
i, j: 10, 5
i, j: 10, 10
Go語(yǔ)言支持匿名函數(shù),即函數(shù)可以像普通變量一樣被傳遞或使用。
閉包是“函數(shù)”和“引用環(huán)境”組成的整體。
func anonymous(n int) func() {
return func() {
n++ //對(duì)外部變量加1
fmt.Println(n)
}
}
func anonymous2(n int) func() {
sum := n
a := func() { //把匿名函數(shù)作為值賦給變量a(Go不允許函數(shù)嵌套,但你可以利用匿名函數(shù)實(shí)現(xiàn)函數(shù)嵌套)
fmt.Println(sum + 1) //調(diào)用本函數(shù)外的變量,這里沒(méi)有()匿名函數(shù)不會(huì)馬上執(zhí)行
}
return a
}
fmt.Println("---------anonymous func--------")
anony := anonymous(10)
anony()
anony1 := anonymous(20)
anony1()
/**
*再次調(diào)用anony()函數(shù),結(jié)果是12,由此得出以下兩點(diǎn)
* 1、內(nèi)函數(shù)對(duì)外函數(shù)的變量的修改,是對(duì)變量的引用
* 2、變量被引用后,它所在的函數(shù)結(jié)束,該變量不會(huì)馬上銷(xiāo)毀
**/
anony()
anony1()
fmt.Println("---------anonymous2----------")
an := anonymous2(10)
an()
an2 := anonymous2(20)
an2()
an()
an2()
輸出:
---------anonymous func--------
11
21
12
22
---------anonymous2----------
11
21
11
21
閉包函數(shù)出現(xiàn)的條件:
1.被嵌套的函數(shù)引用到非本函數(shù)的外部變量,而且這外部變量不是“全局變量”;
2.嵌套的函數(shù)被獨(dú)立了出來(lái)(被父函數(shù)返回或賦值 變成了獨(dú)立的個(gè)體), 而被引用的變量所在的父函數(shù)已結(jié)束。
對(duì)象是附有行為的數(shù)據(jù),而閉包是附有數(shù)據(jù)的行為。
匿名函數(shù)執(zhí)行
匿名函數(shù)最后括號(hào)中加參數(shù),匿名函數(shù)立即執(zhí)行,沒(méi)有括號(hào)或括號(hào)中為空,則需要傳參。例:
fmt.Println("-----------匿名函數(shù)的執(zhí)行----------")
m, n := func(i, j int) (m, n int) { // x y 為函數(shù)返回值
return j, i
}(1, 9) // 直接創(chuàng)建匿名函數(shù)并執(zhí)行
fmt.Println(m, n)
f := func(i, j int) (result int) { // f 為函數(shù)地址
result = i + j
return result
}
fmt.Println(f(1, 2))
輸出:
-----------匿名函數(shù)的執(zhí)行----------
9 1
3
錯(cuò)誤: expression in go/defer must be function call
go關(guān)鍵字后跟匿名函數(shù)報(bào)錯(cuò): expression in go/defer must be function call,在匿名函數(shù)后加括號(hào)則可。例:
func smtp() error {
return nil
}
go func() {
err := smtp()
if err != nil {
fmt.Printf(err.Error())
}
}()
若去掉上面代碼中的空括號(hào)會(huì)報(bào)錯(cuò)。
加()封裝成表達(dá)式。
參考資料: