golang閉包裡的坑

2021-08-23 14:23:56 字數 1916 閱讀 6451

介紹

go的閉包是乙個很有用的東西。但是如果你不了解閉包是如何工作的,那麼他也會給你帶來一堆的bug。這裡我會拿出go in action這本書的一部分**,來說一說在使用閉包的時候可能遇到的坑。全部的**在github上。

閉包的坑

首先看一段**:

search/search.go

// launch a goroutine for each feed to find the results.

for _, feed := range feeds

37 // launch the goroutine to perform the search.

go func(matcher matcher, feed *feed) (matcher, feed)

}

這段**從30行開始遍歷乙個feed的slice。在for range語句中宣告的feed變數的值在每乙個迴圈中都不同。之後從32行的**在檢查乙個某個特定的key值是否有值,如果不存在則賦乙個預設值。和feed變數一樣,matcher的值也是每個迴圈都不一樣。

現在我們可以跳到38行到41行。這幾行**顯然還是在for range迴圈中的。這裡我們定義了乙個匿名函式,並把這個函式做為乙個goroutine執行。這個匿名函式接受兩個引數,第乙個是matcher型別的值,第二個是乙個feed型別的指標。在地41行,我們可以蛋刀matcher和feed兩個變數被傳入了匿名函式中。

這個匿名函式在第39行的實現很有意思。這裡我們可以看到乙個對match方法的呼叫。這個方法接受4個引數,如果你仔細看的話,前兩個引數就是我們定義匿名函式宣告的而兩個引數。後面的兩個我們沒有在匿名函式中宣告。而是作為變數直接在匿名函式使用了。

search/search.go

// launch the goroutine to perform the search.

go func(matcher matcher, feed *feed) (matcher, feed)

}

變數searchterm和results是定義在閉包外部的。我們可以在匿名函式內部直接使用,而不必作為引數傳入後再使用。這裡就會有乙個問題:我們為什麼要把變數matcher和feed作為引數傳入而其他的兩個不是呢?

我在一開始就指出,matcher和feed兩個變數的值是如何在每乙個for range迴圈中改變的。searchterm和results的值不會隨著迴圈而改變,他們的值在每乙個goroutine的生命週期中都是常量。當然,這個goroutine就是使用的匿名函式。那麼,為什麼要這麼做呢?

當我們在匿名函式閉包中使用乙個變數的時候,我們不必在匿名函式宣告的時候作為引數傳遞。這個匿名函式閉包可以直接訪問到定義在其外部的變數,也就是說對這個變數的修改會在匿名函式閉包內部體現出來,也就是這裡的goroutine。如果我們把matcher和feed變數這樣使用,而不是把他們作為引數傳入匿名函式閉包。那麼多數情況下gotoutine只會處理for range迴圈的最後乙個值。

在這個例子中,所有的goroutine都會併發執行。for range迴圈也許在第乙個最多第二個goroutine還在執行的時候就執行完了,matcher和feed變數只會有最後一次迴圈時候的值。也就是說即使不是全部的goroutine也是大部分的goroutine會處理這些變數的相同的值。這種情況適用於searchterm和results變數,因為他們不會在迴圈中改變值。

結論

幸好我們可以宣告可以接收引數的匿名函式,這些型別的閉包問題也就引刃而解。在我們上面的例子中,當每乙個匿名函式都宣告在for range的作用域內的時候,matcher和feed變數的值在作為引數傳入匿名函式閉包的時候也就同時被鎖定。在使用閉包訪問外部變數的時候,問問你自己這個變數時候會發生改變,這樣的改變對閉包的執行有什麼影響。

golang閉包裡的坑

介紹 go的閉包是乙個很有用的東西。但是如果你不了解閉包是如何工作的,那麼他也會給你帶來一堆的bug。這裡我會拿出go in action這本書的一部分 來說一說在使用閉包的時候可能遇到的坑。全部的 在github上。閉包的坑 首先看一段 search search.go 29 launch a g...

golang閉包裡的坑

介紹 go的閉包是乙個很有用的東西。但是如果你不了解閉包是如何工作的,那麼他也會給你帶來一堆的bug。這裡我會拿出go in action這本書的一部分 來說一說在使用閉包的時候可能遇到的坑。全部的 在github上。閉包的坑 首先看一段 search search.go 29 launch a g...

python裡的閉包

1 定義乙個函式 2def test number 34 在函式內部再定義乙個函式,並且這個函式用到了外邊函式的變數,那麼稱裡面 的這個函式為閉包 5def test in number in 6print in test in 函式,number in is d number in 7return...