go語言中的閉包
阿新 • • 發佈:2020-12-15
技術標籤:go
閉包
閉包是什麼?
閉包是一個函式,這個函式包含了他外部作用域的變數
函式可以作為返回值
函式內部查詢變數的順序,先自己內部找,找不到再往外層找
如何形成閉包結構
內層函式+外層函式區域性變數(可以是入參或者定義的區域性變數) = 閉包結構
- 如果將一個內層函式作為函式返回值
- 內層函式中又涉及到外層函式的區域性變數(自己定義或者外部傳進來的引數,都是區域性變數)
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提供的介面是需要傳參的。
這個時候,你可能會想到兩種解決方案:
- 聯絡A部門更改介面A,讓其接收傳引數的函式
A部門直接拒絕了你,理由就是這個介面一直這樣使用,要是更改,工作量大,並且發出去的裝置存在相容性問題 - 聯絡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)
}