【GoLang】golang 閉包 closure 參數(shù)傳遞的蹊蹺扳躬!

結(jié)論:
閉包函數(shù)可以直接引用外層代碼定義的變量,
但是甚亭,注意贷币,閉包函數(shù)里面引用的是變量的地址,
當(dāng)goroutine被調(diào)度時亏狰,改地址的值才會被傳遞給goroutine 函數(shù)役纹。

介紹
go的閉包是一個很有用的東西。但是如果你不了解閉包是如何工作的暇唾,那么他也會給你帶來一堆的bug促脉。這里我會拿出Go In Action這本書的一部分代碼,來說一說在使用閉包的時候可能遇到的坑策州。全部的代碼在github上瘸味。

閉包的坑
首先看一段代碼:

search/search.go
// Launch a goroutine for each feed to find the results.
for _, feed := range feeds {
// Retrieve a matcher for the search.
matcher, exists := matchers[feed.Type]
if !exists {
   matcher = matchers["default"]
}
// Launch the goroutine to perform the search.
go func(matcher Matcher, feed *Feed) {
   Match(matcher, feed, searchTerm, results)
   waitGroup.Done()
}(matcher, feed)
}

這段代碼從30行開始遍歷一個Feed的slice。在for range語句中聲明的feed變量的值在每一個循環(huán)中都不同够挂。之后從32行的代碼在檢查一個某個特定的key值是否有值旁仿,如果不存在則賦一個默認(rèn)值。和feed變量一樣下硕,matcher的值也是每個循環(huán)都不一樣丁逝。
現(xiàn)在我們可以跳到38行到41行。這幾行代碼顯然還是在for range循環(huán)中的梭姓。這里我們定義了一個匿名函數(shù)霜幼,并把這個函數(shù)做為一個goroutine運(yùn)行。這個匿名函數(shù)接受兩個參數(shù)誉尖,第一個是Matcher類型的值罪既,第二個是一個Feed類型的指針。在地41行铡恕,我們可以蛋刀matcher和feed兩個變量被傳入了匿名函數(shù)中琢感。
這個匿名函數(shù)在第39行的實現(xiàn)很有意思。這里我們可以看到一個對Match方法的調(diào)用探熔。這個方法接受4個參數(shù)驹针,如果你仔細(xì)看的話,前兩個參數(shù)就是我們定義匿名函數(shù)聲明的而兩個參數(shù)诀艰。后面的兩個我們沒有在匿名函數(shù)中聲明柬甥。而是作為變量直接在匿名函數(shù)使用了饮六。

search/search.go
// Launch the goroutine to perform the search.
go func(matcher Matcher, feed *Feed) {
   Match(matcher, feed, searchTerm, results)
   waitGroup.Done()
}(matcher, feed)
}

變量searchTerm和results是定義在閉包外部的。我們可以在匿名函數(shù)內(nèi)部直接使用苛蒲,而不必作為參數(shù)傳入后再使用卤橄。這里就會有一個問題:我們?yōu)槭裁匆炎兞縨atcher和feed作為參數(shù)傳入而其他的兩個不是呢?
我在一開始就指出臂外,matcher和feed兩個變量的值是如何在每一個for range循環(huán)中改變的窟扑。searchTerm和results的值不會隨著循環(huán)而改變,他們的值在每一個goroutine的生命周期中都是常量漏健。當(dāng)然嚎货,這個goroutine就是使用的匿名函數(shù)。那么漾肮,為什么要這么做呢厂抖?
當(dāng)我們在匿名函數(shù)閉包中使用一個變量的時候,我們不必在匿名函數(shù)聲明的時候作為參數(shù)傳遞克懊。這個匿名函數(shù)閉包可以直接訪問到定義在其外部的變量忱辅,也就是說對這個變量的修改會在匿名函數(shù)閉包內(nèi)部體現(xiàn)出來,也就是這里的goroutine谭溉。如果我們把matcher和feed變量這樣使用墙懂,而不是把他們作為參數(shù)傳入匿名函數(shù)閉包。那么多數(shù)情況下gotoutine只會處理for range循環(huán)的最后一個值扮念。
在這個例子中损搬,所有的goroutine都會并發(fā)執(zhí)行。for range循環(huán)也許在第一個最多第二個goroutine還在運(yùn)行的時候就運(yùn)行完了柜与,matcher和feed變量只會有最后一次循環(huán)時候的值巧勤。也就是說即使不是全部的goroutine也是大部分的goroutine會處理這些變量的相同的值。這種情況適用于searchTerm和results變量弄匕,因為他們不會在循環(huán)中改變值颅悉。

結(jié)論
幸好我們可以聲明可以接收參數(shù)的匿名函數(shù),這些類型的閉包問題也就引刃而解迁匠。在我們上面的例子中剩瓶,當(dāng)每一個匿名函數(shù)都聲明在for range的作用域內(nèi)的時候,matcher和feed變量的值在作為參數(shù)傳入匿名函數(shù)閉包的時候也就同時被鎖定城丧。在使用閉包訪問外部變量的時候延曙,問問你自己這個變量時候會發(fā)生改變,這樣的改變對閉包的運(yùn)行有什么影響亡哄。

參考資料:
http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#closure_for_it_vars
http://studygolang.com/articles/7994
http://studygolang.com/articles/4738
http://blog.csdn.net/htyu_0203_39/article/details/50985187
http://studygolang.com/articles/356
http://www.jb51.net/article/74166.htm
http://www.cnblogs.com/yjf512/archive/2012/12/09/2810313.html
https://www.zhihu.com/question/49341044?from=profile_question_card
http://www.jb51.net/article/81813.htm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枝缔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚊惯,更是在濱河造成了極大的恐慌魂仍,老刑警劉巖拐辽,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異擦酌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)菠劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門赊舶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赶诊,你說我怎么就攤上這事笼平。” “怎么了舔痪?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵寓调,是天一觀的道長。 經(jīng)常有香客問我锄码,道長夺英,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任滋捶,我火速辦了婚禮痛悯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘重窟。我一直安慰自己载萌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布巡扇。 她就那樣靜靜地躺著扭仁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厅翔。 梳的紋絲不亂的頭發(fā)上乖坠,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音知给,去河邊找鬼瓤帚。 笑死,一個胖子當(dāng)著我的面吹牛涩赢,可吹牛的內(nèi)容都是我干的戈次。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼筒扒,長吁一口氣:“原來是場噩夢啊……” “哼怯邪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起花墩,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤悬秉,失蹤者是張志新(化名)和其女友劉穎澄步,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體和泌,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡村缸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了武氓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梯皿。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖县恕,靈堂內(nèi)的尸體忽然破棺而出东羹,到底是詐尸還是另有隱情,我是刑警寧澤忠烛,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布属提,位于F島的核電站,受9級特大地震影響美尸,放射性物質(zhì)發(fā)生泄漏冤议。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一火惊、第九天 我趴在偏房一處隱蔽的房頂上張望求类。 院中可真熱鬧,春花似錦屹耐、人聲如沸尸疆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寿弱。三九已至,卻和暖如春按灶,著一層夾襖步出監(jiān)牢的瞬間症革,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工鸯旁, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留噪矛,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓铺罢,卻偏偏與公主長得像艇挨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子韭赘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容