1.閉包的概念
閉包并不是什么新奇的概念,它早在高級語言開始發(fā)展的年代就產(chǎn)生了。閉包(Closure)是詞法閉包(Lexical Closure)的簡稱翩概。
閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實體藻糖。在實現(xiàn)深約束時,需要創(chuàng)建一個能顯式表示引用環(huán)境的東西晒哄,并將它與相關(guān)的子程序捆綁在一起睁宰,這樣捆綁起來的整體被稱為閉包。函數(shù) + 引用環(huán)境 = 閉包寝凌。
閉包只是在形式和表現(xiàn)上像函數(shù)柒傻,但實際上不是函數(shù)。函數(shù)是一些可執(zhí)行的代碼较木,這些代碼在函數(shù)被定義后就確定了诅愚,不會在執(zhí)行時發(fā)生變化,所以一個函數(shù)只有一個實例劫映。
閉包在運行時可以有多個實例违孝,不同的引用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實例。閉包在某些編程語言中被稱為Lambda表達(dá)式泳赋。
函數(shù)本身不存儲任何信息雌桑,只有與引用環(huán)境結(jié)合后形成的閉包才具有“記憶性”。函數(shù)是編譯器靜態(tài)的概念祖今,而閉包是運行期動態(tài)的概念校坑。對象是附有行為的數(shù)據(jù),而閉包是附有數(shù)據(jù)的行為千诬。
2.閉包的優(yōu)點
(1)加強(qiáng)模塊化耍目。閉包有益于模塊化編程,便于以簡單的方式開發(fā)較小的模塊徐绑,從而提高開發(fā)速度和程序的可復(fù)用性邪驮。和沒有使用閉包的程序相比,使用閉包可將模塊劃分得更小傲茄。
比如要計算一個數(shù)組中所有數(shù)字的和毅访,只需要循環(huán)遍歷數(shù)組,把遍歷到的數(shù)字加起來就行了盘榨。如果現(xiàn)在要計算所有元素的積喻粹,又或者要打印所有的元素呢?解決這些問題都要對數(shù)組進(jìn)行遍歷草巡,如果是在不支持閉包的語言中守呜,程序員不得不一次又一次重復(fù)地寫循環(huán)語句。而這在支持閉包的語言中是不必要的山憨。這種處理方法多少有點像回調(diào)函數(shù)查乒,不過要比回調(diào)函數(shù)寫法更簡單,功能更強(qiáng)大萍歉。
(2)抽象侣颂。閉包是數(shù)據(jù)和行為的組合,這使得閉包具有較好的抽象能力枪孩。
(3)簡化代碼。一個編程語言需要以下特性來支持閉包。
- 函數(shù)是一階值(First-class value蔑舞,一等公民)拒担,即函數(shù)可以作為另一個函數(shù)的返回值或參數(shù),還可以作為一個變量的值攻询。
- 函數(shù)可以嵌套定義从撼,即在一個函數(shù)內(nèi)部可以定義另一個函數(shù)。
- 允許定義匿名函數(shù)钧栖。
- 可以捕獲引用環(huán)境低零,并把引用環(huán)境和函數(shù)代碼組成一個可調(diào)用的實體。
3.使用閉包函數(shù)實現(xiàn)計數(shù)器
package main
import "fmt"
// pos 帶數(shù)據(jù)的函數(shù)
func main() {
pos := adder()
for i := 0; i < 10; i++ {
fmt.Printf("i=%d \t",i)
fmt.Println(pos(i))
}
fmt.Println("----------------------------")
for i := 0; i < 10; i++ {
fmt.Printf("i=%d \t",i)
fmt.Println(pos(i))
}
}
func adder() func(int) int {
sum := 0
return func(x int) int {
fmt.Printf("sum1 = %d \t", sum)
sum += x
fmt.Printf("sum1 = %d \t", sum)
return sum
}
}
由于閉包函數(shù)“捕獲”了和它在同一作用域的其他常量和變量拯杠,所以當(dāng)閉包在任何地方被調(diào)用掏婶,閉包都可以使用這些常量或者變量。它不關(guān)心這些變量是否已經(jīng)超出作用域潭陪,只要閉包還在使用這些變量雄妥,這些變量就依然存在。