Go里有函數(shù)類型的變量,這樣,雖然不能在一個(gè)函數(shù)里直接聲明另一個(gè)函數(shù),但是可以在一個(gè)函數(shù)中聲明一個(gè)函數(shù)類型的變量,此時(shí)的函數(shù)稱為閉包(closure)。
packagemain
import"fmt"
funcmain(){
add:=func(baseint)func(int)(int){
returnfunc(iint)(int){
returnbase+i
}
}
add5:=add(5)
fmt.Println("add5(10)=",add5(10))
}
add是一個(gè)閉包,因?yàn)樗菬o名的函數(shù)類型的變量??梢哉J(rèn)為它是一個(gè)閉包作坊,根據(jù)入?yún)⒎祷?生產(chǎn))一個(gè)閉包。這樣add5就是使用5作為add的參數(shù)得到的一個(gè)閉包。
閉包的聲明是在另一個(gè)函數(shù)的內(nèi)部,形成嵌套。和塊的嵌套一樣,內(nèi)層的變量可以遮蓋同名的外層的變量,而且外層變量可以直接在內(nèi)層使用。如add的base參數(shù)在return返回的閉包的外層,所以它的值5在add返回并賦值給add5后依舊存在。當(dāng)add5執(zhí)行時(shí),參數(shù)i可以從這個(gè)外層得到的base相加,得到結(jié)果15.
其實(shí)理解閉包的最方便的方法就是將閉包函數(shù)看成一個(gè)類,一個(gè)閉包函數(shù)調(diào)用就是實(shí)例化一個(gè)類。
pos和neg分別實(shí)例化了兩個(gè)“閉包類”,在這個(gè)“閉包類”中有個(gè)“閉包全局變量”sum。所以這樣就很好理解返回的結(jié)果了。
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}