Scala中閉包

在Scala中,函數(shù)引入傳入的參數(shù)是再正常不過的事情了,比如
(x: Int) => x > 0中畦浓,唯一在函數(shù)體x > 0中用到的變量是x直奋,即這個函數(shù)的唯一參數(shù)。

除此之外九杂,Scala還支持引用其他地方定義的變量:
(x: Int) => x + more颁湖,這個函數(shù)將more也作為入?yún)ⅲ贿^這個參數(shù)是哪里來的尼酿?從這個函數(shù)的角度來看爷狈,more是一個自由變量,因為函數(shù)字面量本身并沒有給more賦予任何含義裳擎。相反涎永,x是一個綁定變量,因為它在該函數(shù)的上下文里有明確的定義:它被定義為該函數(shù)的唯一參數(shù)。如果單獨使用這個函數(shù)字面量羡微,而沒有在任何處于作用域內(nèi)的地方定義more谷饿,編譯器將報錯:

scala> (x: Int) => x + more
<console>:12: error: not found: value more
       (x: Int) => x + more

另一方面,只要能找到名為more的變量妈倔,同樣的函數(shù)字面量就能正常工作:

scala> var more = 1
more: Int = 1

scala> val addMore = (x: Int) => x + more
addMore: Int => Int = $$Lambda$1104/583744857@33e4b9c4

scala> addMore(10)
res0: Int = 11

運行時從這個函數(shù)字面量創(chuàng)建出來的函數(shù)值(對象)被稱為閉包博投。該名稱源于“捕獲”其自由變量從而“閉合”該函數(shù)字面量的動作。沒有自由變量的函數(shù)字面量盯蝴,比如(x: Int) => x + 1毅哗,稱為閉合語(這里的語指的是一段源代碼)。因此捧挺,運行時從這個函數(shù)字面量創(chuàng)建出來的函數(shù)值嚴(yán)格來說并不是一個閉包虑绵,因為(x: Int) => x + 1按照目前這個寫法已經(jīng)是閉合的了。而運行時從任何帶有自由變量的函數(shù)字面量闽烙,比如(x: Int) => x + more創(chuàng)建的函數(shù)翅睛,按照定義,要求捕獲到它的自由變量more的綁定黑竞。相應(yīng)的函數(shù)值結(jié)果(包含指向被捕獲的more變量的引用)就被稱為閉包捕发,因為函數(shù)值是通過閉合這個開放語的動作產(chǎn)生的。

這個例子帶來一個問題:如果more在閉包創(chuàng)建以后被改變會發(fā)生什么很魂?在Scala中扎酷,答案是閉包能夠看到這個改變,參考下面的例子:

scala> more = 9999
more: Int = 9999

scala> addMore(10)
res1: Int = 10009

很符合直覺的是莫换,Scala的閉包捕獲的是變量本身霞玄,而不是變量引用的值。正如前面示例所展示的拉岁,為(x: Int) => x + more創(chuàng)建的閉包能夠看到閉包外對more的修改坷剧。反過來也是成立的:閉包對捕獲到的變量的修改也能在閉包外被看到。參考下面的例子:

scala> val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10)

scala> var sum = 0
sum: Int = 0

scala> someNumbers.foreach(sum += _)

scala> sum
res3: Int = -11

這個例子通過遍歷的方式來對List中的數(shù)字求和喊暖。sum這個變量位于函數(shù)字面量sum += _的外圍作用域惫企,這個函數(shù)將數(shù)字加給sum。雖然運行時是這個閉包對sum進行的修改陵叽,最終的結(jié)果-11仍然能被閉包外部看到狞尔。

那么,如果一個閉包訪問了某個隨著程序運行會產(chǎn)生多個副本的變量會如何呢巩掺?例如偏序,如果一個閉包使用了某個函數(shù)的局部變量,而這個函數(shù)又被調(diào)用了多次胖替,會怎么樣研儒?閉包每次訪問到的是這個變量的哪一個實例呢豫缨?

答案是:閉包引用的實例是在閉包被創(chuàng)建時活躍的那一個。參考下面的函數(shù)端朵,函數(shù)創(chuàng)建并返回more閉包的函數(shù)

def makeIncreaser(more: Int) = (x: Int) => x + more

該函數(shù)每調(diào)用一次好芭,就會創(chuàng)建一個新的閉包。每個閉包都會訪問那個在它創(chuàng)建時活躍的變量more

scala> val inc1 = makeIncreaser(1)
inc1: Int => Int = $$Lambda$1269/1504482477@1179731c

scala> val inc9999 = makeIncreaser(9999)
inc9999: Int => Int = $$Lambda$1269/1504482477@2dba6013

當(dāng)調(diào)用makeIncreaser(1)時冲呢,一個捕獲了more的綁定值為1的閉包就被創(chuàng)建并返回舍败。同理,當(dāng)調(diào)用makeIncreaser(9999)時敬拓,返回的是一個捕獲了more的綁定值9999的閉包邻薯。當(dāng)你將這些閉包應(yīng)用到入?yún)r,其返回結(jié)果取決于閉包創(chuàng)建時more的定義

scala> inc1(10)
res4: Int = 11

scala> inc9999(10)
res5: Int = 10009

這里恩尾,more是某次方法調(diào)用的入?yún)⒊谒担椒ㄒ呀?jīng)返回了挽懦,不過這并沒有影響翰意。Scala編譯器會重新組織和安排,讓被捕獲的參數(shù)在堆上繼續(xù)存活信柿。這樣的安排都是由編譯器自動完成的冀偶,使用者并不需要關(guān)心。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渔嚷,一起剝皮案震驚了整個濱河市进鸠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌形病,老刑警劉巖客年,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異漠吻,居然都是意外死亡量瓜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門途乃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绍傲,“玉大人,你說我怎么就攤上這事耍共√瘫” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵试读,是天一觀的道長杠纵。 經(jīng)常有香客問我,道長钩骇,這世上最難降的妖魔是什么比藻? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任骇塘,我火速辦了婚禮,結(jié)果婚禮上韩容,老公的妹妹穿的比我還像新娘款违。我一直安慰自己,他們只是感情好群凶,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布插爹。 她就那樣靜靜地躺著,像睡著了一般请梢。 火紅的嫁衣襯著肌膚如雪赠尾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天毅弧,我揣著相機與錄音气嫁,去河邊找鬼。 笑死够坐,一個胖子當(dāng)著我的面吹牛寸宵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播元咙,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼梯影,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了庶香?” 一聲冷哼從身側(cè)響起甲棍,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赶掖,沒想到半個月后感猛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡奢赂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年陪白,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呈驶。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡拷泽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袖瞻,到底是詐尸還是另有隱情司致,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布聋迎,位于F島的核電站脂矫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏霉晕。R本人自食惡果不足惜庭再,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一捞奕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拄轻,春花似錦颅围、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至斧抱,卻和暖如春常拓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辉浦。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工弄抬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宪郊。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓掂恕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親废膘。 傳聞我的和親對象是個殘疾皇子竹海,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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