Go語言之旅 閉包

2021-10-10 20:46:10 字數 1716 閱讀 6988

閉包是在詞法上下文中引用了自由變數的函式,這種說法可能太過學術化了,很難理解。

用通俗的話來說, 閉包相當於在乙個函式中,去捕獲自由變數(在函式外部定義但在函式內被引用的變數) 。當脫離了捕獲該自由變數的上下文,依舊可以使用該自由變數。

我們來看乙個例子

func

test

(x int

)func()

}func

main()

輸出結果為 1

test返回的匿名函式會引用上下文環境變數 x, 當該函式在 main 執行的時候, 它依然可以正確讀取 x 的值, 這種現象就稱之為閉包

首先我們可以想到這個變數應該不會是在棧中進行分配的,而是在堆中進行分配。如果該變數在棧中進行分配的話,函式返回之後,該變數應該會被**,所以只可能是在堆中進行分配。

在繼續** 閉包的實現問題之前,我們可以先去了解一下escape analyze機制

escape analyze(逃逸分析機制) 是一種確定指標動態範圍的方法-它可以分析程式在哪些地方可以訪問到指標,它涉及指標分析和形狀分析。

舉個例子

funcf(

)*cursor

這種返回區域性變數的辦法在c語言上是不允許的,但是在go語言中是明確規定為合法的,語言會自動識別這種情況並在堆上分配相應的記憶體,而不是在函式棧上分配記憶體。

我們可以通過

go build --gcflags=-m main.go

我們可以看到輸出

./main.go:20: moved to heap: c .

/main.go:23: &c escapes to heap 表示c逃逸了,被移到堆中。

我們重新回到閉包的實現來看,閉包既然是函式和它引用的環境組成,那是不是我們可以通過乙個類去進行表示閉包呢?(如c++中的lambda表示式 一樣,通過乙個匿名類來標誌閉包)

我們可以將上述來這樣理解

type closure struct

縮小變數作用域,減少對全域性變數的汙染,並且閉包可以讓我們不用傳遞引數就可以讀取或者修改環境狀態。

閉包可以作為一種有自身狀態的函式

package main

import

("fmt"

)func

adder()

func()

int}

func

main()

fmt.

println

(myadder()

) fmt.

println

(myadder()

)}

輸出

11

12

小結

go語言能通過escape analyze識別出變數的作用域,自動將變數在堆上分配。將閉包環境變數在堆上分配是go實現閉包的基礎。

返回閉包時並不是單純返回乙個函式,而是返回了乙個結構體,記錄下函式返回位址和引用的環境中的變數位址。

閉包可以縮小變數作用域,減少對全域性變數的汙染,可以讓我們不用傳遞引數就可以讀取或者修改環境狀態

Go語言之函式使用 8 閉包

閉包就是乙個函式和與其相關的引用環境組合的乙個整體 實體 package main import fmt func addupper str string func int int func main 案例分析 1 addupper會返回乙個匿名函式 func x int int2 該匿名函式引用到...

go語言之旅 二

package main import fmt func main if else if x 2 0 else num 1 多分支 go語言只有一種迴圈結構,即for迴圈。語法如下 sum 0 for i 0 i 10 i 注意 for語句後面沒有小括號。for語句前後兩部分都是可以省略的,如 su...

go語言之旅 三

指標 go與c語言一樣,擁有指標。指標儲存了值的記憶體位址。型別 t是指向t型別值的指標。其零值為nil。定義如下 var p int 與 c 不同,go 沒有指標運算。結構體 與c語言類似,除了定義方式不同之外,其他都與c相同,如訪問方式 等。陣列 型別 n t 表示擁有 n 個 t 型別的值的陣...