Go 閉包的實現

Wu_XMing發表於2018-09-30

閉包是由函式及其相關引用環境組合而成的實體(即:閉包=函式+引用環境)。

Go中的閉包

func f() func() int {
	i:=0
	return func() int {
		i++
		return i
	}
}
複製程式碼

函式f返回了一個函式,返回的這個函式,返回的這個函式就是一個閉包。這個函式本身沒有定義變數的,而是引用了它所在的環境(函式f)中的變數i。

         c1 := f()
	 c2 := f()
	fmt.Println(c1()) //  output: 1
	fmt.Println(c2()) //  output: 1
	fmt.Println(c2()) //  output: 2
	fmt.Println(c1()) //  output: 2
複製程式碼

函式f每呼叫一次,就形成了一個新的環境,對應的閉包中,函式都是同一個函式,環境卻是引用不同的環境。

閉包環境中引用的變數是不能夠在棧上分配的,而是在堆上分配。因為如果引用的變數在棧上分配,那麼該變數會跟隨函式f返回之後回收,那麼閉包函式就不可能訪問未分配的一個變數,即未宣告的變數,之所以能夠再堆上分配,而不是在棧上分配,是Go的一個語言特性----escape analyze(能夠自動分析出變數的作用範圍,是否將變數分配堆上)。

閉包的底層實現

Go在底層使用類似結構體的形式表示一個閉包。

我們可以把上面的閉包表示成這樣,即:

type  Closure struct{
    func()() //匿名函式地址,當然語法要求一定要有變數名,這裡只是為了表達匿名的含義
    i *int //引用的變數地址
}
複製程式碼

小結

  1. Go語言支援閉包

  2. Go語言能通過escape analyze識別出變數的作用域,自動將變數在堆上分配。將閉包環境變數在堆上分配是Go實現閉包的基礎。

  3. 返回閉包時並不是單純返回一個函式,而是返回了一個結構體,記錄下函式返回地址和引用的環境中的變數地址。

參考:

tiancaiamao.gitbooks.io/go-internal…

相關文章