GO語言的匿名函數(shù)就是閉包
基本概念
閉包是可以包含自由(未綁定到特定對象)變量的代碼塊,這些變量不在這個代碼塊內(nèi)或者任何全局上下文中定義察纯,而是在定義代碼塊的環(huán)境中定義帕棉。要執(zhí)行的代碼塊(由于自由變量包含
在代碼塊中,所以這些自由變量以及它們引用的對象沒有被釋放)為自由變量提供綁定的計算環(huán)境(作用域)饼记。
閉包的價值
閉包的價值在于可以作為函數(shù)對象或者匿名函數(shù)香伴,對于類型系統(tǒng)而言,這意味著不僅要表示數(shù)據(jù)還要表示代碼具则。支持閉包的多數(shù)語言都將函數(shù)作為第一級對象即纲,就是說這些函數(shù)可以存儲到
變量中作為參數(shù)傳遞給其他函數(shù),最重要的是能夠被函數(shù)動態(tài)創(chuàng)建和返回博肋。
Go語言中的閉包
Go語言中的閉包同樣也會引用到函數(shù)外的變量低斋。閉包的實現(xiàn)確保只要閉包還被使用,那么被閉包引用的變量會一直存在匪凡。例:
// 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)
}
}() //末尾的括號表明匿名函數(shù)被調(diào)用膊畴,并將返回的函數(shù)指針賦給變量a
a()
j *= 2
a()
}
輸出:
i, j: 10, 5
i, j: 10, 10
Go語言支持匿名函數(shù),即函數(shù)可以像普通變量一樣被傳遞或使用病游。
閉包是“函數(shù)”和“引用環(huán)境”組成的整體唇跨。
func anonymous(n int) func() {
return func() {
n++ //對外部變量加1
fmt.Println(n)
}
}
func anonymous2(n int) func() {
sum := n
a := func() { //把匿名函數(shù)作為值賦給變量a(Go不允許函數(shù)嵌套稠通,但你可以利用匿名函數(shù)實現(xiàn)函數(shù)嵌套)
fmt.Println(sum + 1) //調(diào)用本函數(shù)外的變量,這里沒有()匿名函數(shù)不會馬上執(zhí)行
}
return a
}
fmt.Println("---------anonymous func--------")
anony := anonymous(10)
anony()
anony1 := anonymous(20)
anony1()
/**
*再次調(diào)用anony()函數(shù)买猖,結果是12改橘,由此得出以下兩點
* 1、內(nèi)函數(shù)對外函數(shù)的變量的修改玉控,是對變量的引用
* 2飞主、變量被引用后,它所在的函數(shù)結束高诺,該變量不會馬上銷毀
**/
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ù)被獨立了出來(被父函數(shù)返回或賦值 變成了獨立的個體), 而被引用的變量所在的父函數(shù)已結束懒叛。
對象是附有行為的數(shù)據(jù)丸冕,而閉包是附有數(shù)據(jù)的行為。
匿名函數(shù)執(zhí)行
匿名函數(shù)最后括號中加參數(shù)薛窥,匿名函數(shù)立即執(zhí)行胖烛,沒有括號或括號中為空,則需要傳參诅迷。例:
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
錯誤: expression in go/defer must be function call
go關鍵字后跟匿名函數(shù)報錯: expression in go/defer must be function call佩番,在匿名函數(shù)后加括號則可。例:
func smtp() error {
return nil
}
go func() {
err := smtp()
if err != nil {
fmt.Printf(err.Error())
}
}()
若去掉上面代碼中的空括號會報錯罢杉。
加()封裝成表達式趟畏。
參考資料: