Go xmas2020 全英課程 09 學習筆記、Closures
阿新 • • 發佈:2022-04-05
課程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主講老師 Matt Holiday
09-Closures
變數的生命週期可以超過變數宣告上下文的範圍
左側 f 只是函式指標,右側 f 則是閉包。
Slice
需要一個特定的閉包簽名函式。在閉包的上下文中,我唯一傳遞給我的閉包是 i、j 他們是整數,ss 也是這個函式的一部分雖然沒有被明確傳入。
package main import "fmt" func do(d func()) { d() } func main() { for i := 0; i < 4; i++ { v := func() { fmt.Printf("%d @ %p\n", i, &i) } do(v) } }
0 @ 0xc000016088
1 @ 0xc000016088
2 @ 0xc000016088
3 @ 0xc000016088
package main
import "fmt"
func main() {
s := make([]func(), 4)
for i := 0; i < 4; i++ {
s[i] = func() {
fmt.Printf("%d @ %p\n", i, &i)
}
}
for i := 0; i < 4; i++ {
s[i]()
}
}
4 @ 0xc000016088
4 @ 0xc000016088
4 @ 0xc000016088
4 @ 0xc000016088
當封閉 i
變數時,每個閉包需要一個引用。四個匿名函式引用的都是同一個 i
i
值為 4。i
並沒有被垃圾回收,因為它仍被 4
個匿名閉包函式所引用。每次列印都是 4
比如傳入一個閉包函式作為回撥函式的時候,所引用的值在回撥執行前會發生改變,那會出現大問題。
在第一個迴圈內建立一個新變數,每次迴圈宣告初始化一個新變數,每個閉包函式會引用這個新變數,每個 i2
地址不一樣。
for i := 0; i < 4; i++ {
i2 := i // closure capture
s[i] = func() {
fmt.Printf("%d @ %p\n", i, &i)
}
閉包是一種函式,呼叫具有來自函式外部的附加資料。
gotcha
,因為閉包通過引用封閉,如果閉包是非同步執行的,那麼我封閉(封蓋)的變數可能會發生改變。正如前面的例子,修復方法就是建立一個對應的本地副本,讓閉包函式關閉(封蓋)本地副本,這樣副本的值就固定了。