課程地址 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 ,因為閉包通過參考封閉,如果閉包是異步執行的,那么我封閉(封蓋)的變數可能會發生改變,正如前面的例子,修復方法就是創建一個對應的本地副本,讓閉包函式關閉(封蓋)本地副本,這樣副本的值就固定了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/455632.html
標籤:其他
