日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
學(xué)習(xí)Scala的閉包

到本章這里,所有函數(shù)文本的例子僅參考了傳入的參數(shù)。例如,(x: Int) => x > 0里,函數(shù)體用到的***變量,x > 0,是x,被定義為函數(shù)參數(shù)。然而也可以參考定義在其它地方的變量:

員工經(jīng)過長期磨合與沉淀,具備了協(xié)作精神,得以通過團隊的力量開發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)堅持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因為“專注所以專業(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡單”。公司專注于為企業(yè)提供成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設(shè)、微信公眾號開發(fā)、電商網(wǎng)站開發(fā),小程序定制開發(fā),軟件按需定制設(shè)計等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。

 
 
 
  1. (x: Int) => x + more // more是多少? 

編輯推薦:Scala編程語言專題

函數(shù)把“more”加入?yún)⒖迹裁词莔ore呢?從這個函數(shù)的視點來看,more是個自由變量:free variable,因為函數(shù)文本自身沒有給出其含義。相對的,x變量是一個綁定變量:bound variable,因為它在函數(shù)的上下文中有明確意義:被定義為函數(shù)的***參數(shù),一個Int。如果你嘗試獨立使用這個函數(shù)文本,范圍內(nèi)沒有任何more的定義,編譯器會報錯說:

 
 
 
  1. scala> (x: Int) => x + more  
  2. < console>:5: error: not found: value more  
  3.  (x: Int) => x + more  
  4.  ?  

另一方面,只要有一個叫做more的什么東西同樣的函數(shù)文本將工作正常:

 
 
 
  1. scala> var more = 1 
  2. more: Int = 1 
  3. scala> val addMore = (x: Int) => x + more  
  4. addMore: (Int) => Int = < function>  
  5. scala> addMore(10)  
  6. res19: Int = 11 

依照這個函數(shù)文本在運行時創(chuàng)建的函數(shù)值(對象)被稱為
閉包:closure。名稱源自于通過“捕獲”自由變量的綁定對函數(shù)文本執(zhí)行的“關(guān)閉”行動。不帶自由變量的函數(shù)文本,如(x: Int) => x + 1,被稱為
封閉術(shù)語:closed term,這里
術(shù)語:term指的是一小部分源代碼。因此依照這個函數(shù)文本在運行時創(chuàng)建的函數(shù)值嚴(yán)格意義上來講就不是閉包,因為(x: Int) => x + 1在編寫的時候就已經(jīng)封閉了。但任何帶有自由變量的函數(shù)文本,如(x: Int) => x + more,都是
開放術(shù)語:open term。因此,任何依照(x: Int) => x + more在運行期創(chuàng)建的函數(shù)值將必須捕獲它的自由變量,more,的綁定。由于函數(shù)值是關(guān)閉這個開放術(shù)語(x: Int) => x + more的行動的最終產(chǎn)物,得到的函數(shù)值將包含一個指向捕獲的more變量的參考,因此被稱為閉包。

這個例子帶來一個問題:如果more在閉包創(chuàng)建之后被改變了會發(fā)生什么事?Scala里,答案是閉包看到了這個變化。如下:

 
 
 
  1. scala> more = 9999 
  2. more: Int = 9999 
  3. scala> addMore(10)  
  4. res21: Int = 10009 

直覺上,Scala的閉包捕獲了變量本身,而不是變量指向的值。
相對的,Java的內(nèi)部類根本不允許你訪問外圍范圍內(nèi)可以改變的變量,因此到底是捕獲了變量還是捕獲了它當(dāng)前具有的值就沒有差別了。就像前面演示的例子,依照(x: Int) => x + more創(chuàng)建的閉包看到了閉包之外做出的對more的變化。反過來也同樣。閉包對捕獲變量作出的改變在閉包之外也可見。下面是一個例子:

 
 
 
  1. scala> val someNumbers = List(-11, -10, -5, 0, 5, 10)  
  2. someNumbers: List[Int] = List(-11, -10, -5, 0, 5, 10)  
  3. scala> var sum = 0 
  4. sum: Int = 0 
  5. scala> someNumbers.foreach(sum += _)  
  6. scala> sum  
  7. res23: Int = -11 

例子用了一個循環(huán)的方式計算List的累加和。變量sum處于函數(shù)文本sum += _的外圍,函數(shù)文本把數(shù)累加到sum上。盡管這是一個在運行期改變sum的閉包,作為結(jié)果的累加值,-11,仍然在閉包之外可見。

如果閉包訪問了某些在程序運行時有若干不同備份的變量會怎樣?例如,如果閉包使用了某個函數(shù)的本地變量,并且函數(shù)被調(diào)用很多次會怎樣?每一次訪問使用的是變量的哪個實例?

僅有一個答案與語言余下的部分共存:使用的實例是那個在閉包被創(chuàng)建的時候活躍的。例如,以下是創(chuàng)建和返回“遞增”閉包的函數(shù):

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

每次函數(shù)被調(diào)用時都會創(chuàng)建一個新閉包。每個閉包都會訪問閉包創(chuàng)建時活躍的more變量。

 
 
 
  1. scala> val inc1 = makeIncreaser(1)  
  2. inc1: (Int) => Int = < function>  
  3. scala> val inc9999 = makeIncreaser(9999)  
  4. inc9999: (Int) => Int = < function>  

調(diào)用makeIncreaser(1)時,捕獲值1當(dāng)作more的綁定的閉包被創(chuàng)建并返回。相似地,調(diào)用makeIncreaser(9999),捕獲值9999當(dāng)作more的閉包被返回。當(dāng)你把這些閉包應(yīng)用到參數(shù)上(本例中,只有一個參數(shù),x,必須被傳入),回來的結(jié)果依賴于閉包被創(chuàng)建時more是如何定義的:

 
 
 
  1. scala> inc1(10)  
  2. res24: Int = 11 
  3. scala> inc9999(10)  
  4. res25: Int = 10009 

盡管本例中more是一個已經(jīng)返回的方法調(diào)用的參數(shù)也沒有區(qū)別。Scala編譯器在這種情況下重新安排了它以使得捕獲的參數(shù)繼續(xù)存在于堆中,而不是堆棧中,因此可以保留在創(chuàng)建它的方法調(diào)用之外。這種重新安排的工作都是自動關(guān)照的,因此你不需要操心。請任意捕獲你想要的變量:val,var,或參數(shù)。

【相關(guān)閱讀】

  1. Scala的偏應(yīng)用函數(shù)
  2. Scala:函數(shù)文本的短格式和占位符語法
  3. 介紹Scala的***類函數(shù)
  4. Scala的本地函數(shù):將私有方法轉(zhuǎn)換為本地方法
  5. Scala中定義函數(shù)的方法:method


當(dāng)前文章:學(xué)習(xí)Scala的閉包
標(biāo)題網(wǎng)址:http://www.dlmjj.cn/article/copeecg.html