php小編魚仔封閉所容納的環境范圍是指封閉環境中所包含的元素、因素和條件。封閉環境是指一個相對封閉、受限制的空間或范圍,可以是物理空間,如實驗室、工廠車間, 也可以是虛擬空間,如計算機網絡。在封閉環境中,各種因素如溫度、濕度、氣體組成等都可以被控制和調節,以達到特定的目的。封閉環境常見于科研實驗、生產制造等領域,對于保證實驗精確性、產品質量等方面起到重要作用。
問題內容
我模仿網上關于閉包的教程,寫了下面的代碼。
func foo1() func() { xvalue := 1 x := &xvalue defer func() { xvalue = 2 }() return func() { *x = *x + 1 fmt.printf("foo1 val = %d\n", *x) } } func main() { f1 := foo1() f1() f1() f1() }
登錄后復制
我很困惑,在執行 f1 := foo1()
后,變量 xvalue
似乎應該被回收,因此使用 *x
應該是錯誤的,但上面的代碼沒有錯誤并且執行罰款,給出輸出
foo1 val = 3 foo1 val = 4 foo1 val = 5
登錄后復制
所以我想知道閉包除了保存指針本身之外還保存了指針的值還是go語言的垃圾回收機制導致xvalue沒有被刪除?
解決方法
在 Go 中,閉包獲取對其關閉的任何變量(的地址)的引用。引用語言參考:
函數文字是閉包:它們可以引用周圍函數中定義的變量。然后,這些變量在周圍的函數和函數文字之間共享,并且只要可訪問,它們就會一直存在。
因此,在您的示例中:
f1 := foo1()
-
使
xValue
變量存在(編譯器可能會在堆上分配它)。它將以其類型的零值 0 開始。使變量
x
存在并為其分配 xValue
的地址。
defer
-red 閉包運行并將值 2 分配給 xValue
。
返回一個關閉變量 x
的閉包。
后一點可能有點棘手:由于返回的閉包引用了變量 x
,編譯器保證即使在 foo
返回后該變量也存在。由于 x
包含 xValue
的地址(因此是對它的實時引用),因此該地址仍然存在,并且不能被垃圾收集。
使用相同的轉義分析方法,編譯器保證 xValue
在其聲明的函數返回后仍然存在。
您執行返回的閉包,該閉包通過指向它的指針修改 xValue
– 這里沒有發生任何魔法。另外兩個調用執行相同的操作。
總而言之,也許您被 C++ 知識絆倒了,一旦從該函數返回控制權,函數中聲明的任何變量都將不再存在,因此該函數外部存在的對該變量的任何引用都將變為無效的。在 Go 中,情況并非如此:在這方面,該語言被顯式定義為安全:編譯器確保任何變量都有適當的分配,以便在返回(或以其他方式傳達)對它的引用時在創建它的函數調用中生存下來。從該函數調用到外部世界。