1. 程式人生 > 其它 >go語言中的閉包

go語言中的閉包

技術標籤:go

閉包

閉包是什麼?
閉包是一個函式,這個函式包含了他外部作用域的變數
函式可以作為返回值
函式內部查詢變數的順序,先自己內部找,找不到再往外層找

如何形成閉包結構
內層函式+外層函式區域性變數(可以是入參或者定義的區域性變數) = 閉包結構

  1. 如果將一個內層函式作為函式返回值
  2. 內層函式中又涉及到外層函式的區域性變數(自己定義或者外部傳進來的引數,都是區域性變數)
    1+2 條件滿足後,就會導致該區域性變數的宣告週期發生改變,外層函式的區域性變數不會隨著外層函式的借宿而銷燬
    將這種內層函式變數和外層區域性變數,統稱為閉包結構
    閉包結構中,區域性變數的宣告週期會發生改變
package
main import "fmt" func main() { // goy語言支援函數語言程式設計: // 支援將一個函式的返回值作為另外一個函式的引數 // 也支援將一個函式作為一個函式的返回值 /** 閉包(closure): */ res1 := increment() fmt.Printf("%T\n", res1) // 區域性變數應該銷燬,但是還是能正常返回 v1 := res1() fmt.Println(v1) fmt.Println("func closure") v2 := res1() fmt.
Println(v2) fmt.Println(res1()) fmt.Println(res1()) fmt.Println(res1()) fmt.Println(res1()) // 使用返回函式再次呼叫 // 每當呼叫 increment的時候 fmt.Println("call again") res2 := increment() v3 := res2() fmt.Println(v3) } /* 1. 如果將一個內層函式作為函式返回值 2. 內層函式中又涉及到外層函式的區域性變數(自己定義或者外部傳進來的引數,都是區域性變數) 3. 1+2 條件滿足後,就會導致該區域性變數的宣告週期發生改變,外層函式的區域性變數不會隨著外層函式的借宿而銷燬 4. 這種內層函式變數和外層區域性變數,統稱為閉包結構 5. 閉包結構中,區域性變數的宣告週期會發生改變 */
func increment() func() int { // 外層函式 // 定義一個區域性變數 i := 0 // 定義一個匿名函式, 並且進行返回 fun := func() int { // 內層函式 i++ return i } // 返回該匿名函式 return fun }

閉包的例子

假設,func oldFun(f func())為一個A庫裡面的老介面,比如是你工作中對接部門給你的介面, 這個介面有是實現你們業務必須呼叫的介面, 而老介面需要呼叫B部門提供的介面func newFun(x, y int),我們明顯看出,老介面只能接受無引數的函式,但是部門B提供的介面是需要傳參的。
這個時候,你可能會想到兩種解決方案:

  1. 聯絡A部門更改介面A,讓其接收傳引數的函式
    A部門直接拒絕了你,理由就是這個介面一直這樣使用,要是更改,工作量大,並且發出去的裝置存在相容性問題
  2. 聯絡B部門更改介面B,去掉介面中需要傳入的引數
    B部門直接拒絕

在苦思良久之後你想到go語言中,有閉包,可以解決這個問題:
解決思路如下:
封裝一個閉包結構,該結構返回一個匿名函式,匿名函式是無引數函式,匿名函式體中呼叫新介面,新介面利用閉包的特性可以在執行時得到入參的兩個值。具體實現程式碼如下:

package main

import "fmt"

/*
閉包是什麼?
閉包是一個函式,這個函式包含了他外部作用域的變數

函式可以作為返回值
函式內部查詢變數的順序,先自己內部找,找不到再往外層找

*/

/*
每次呼叫 increment都會重新生成一個閉包結構中的變數
內層函式+外層函式區域性變數(可以是入參或者定義的區域性變數) = 閉包結構

如果將一個內層函式作為函式返回值
內層函式中又涉及到外層函式的區域性變數(自己定義或者外部傳進來的引數,都是區域性變數)
1+2 條件滿足後,就會導致該區域性變數的宣告週期發生改變,外層函式的區域性變數不會隨著外層函式的借宿而銷燬
這種內層函式變數和外層區域性變數,統稱為閉包結構
閉包結構中,區域性變數的宣告週期會發生改變
*/

// 老的函式介面,只能接受沒有引數
func oldFun(f func()) {
	fmt.Println("this is f1")
	f()
}

// 新的介面
func newFun(x, y int) {
	fmt.Println("this is f2")
	fmt.Print(x + y)
}

//使用閉包介面可以實現將新介面,轉換為老介面
//使用特性   閉包結構
func closureFun(f func(int, int), x, y int) func() {
	// 閉包結構中, x y 變數的生命週期已經發生改變,在任何呼叫匿名函式的地方
	//都可以得到 x, y 的值,從而實現,在oldFun函式呼叫匿名函式的時候,壓棧,調到函式newFun的時候,依舊能獲取到 x y的值
	fmt.Println("closure func")
	tmp := func() {
		fmt.Println("closure tmp func")
		f(x, y)
	}

	return tmp
}

func main() {

	// 匿名函式,立即執行函式
	func(x, y int) {
		fmt.Println(x + y)
	}(1, 2)

	//	閉包
	fmt.Println("-------------closure func--------------")
	fakeOldFun := closureFun(newFun, 2, 3)
	oldFun(fakeOldFun)

}