自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

學習Scala的閉包

開發(fā) 后端
本文節(jié)選自Martin Odersky,Lex Spoon和Bill Venners所著,Regular翻譯的《Programming in Scala》的第八章。Scala是一種針對 JVM 將函數(shù)和面向?qū)ο蠹夹g(shù)組合在一起的編程語言。

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

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

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

函數(shù)把“more”加入?yún)⒖?,但什么是more呢?從這個函數(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ù)值嚴格意義上來講就不是閉包,因為(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)可以改變的變量,因此到底是捕獲了變量還是捕獲了它當前具有的值就沒有差別了。就像前面演示的例子,依照(x: Int) => x + more創(chuàng)建的閉包看到了閉包之外做出的對more的變化。反過來也同樣。閉包對捕獲變量作出的改變在閉包之外也可見。下面是一個例子:

  1. scala> val someNumbers = List(-11, -10, -50510)  
  2. someNumbers: List[Int] = List(-11, -10, -50510)  
  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當作more的綁定的閉包被創(chuàng)建并返回。相似地,調(diào)用makeIncreaser(9999),捕獲值9999當作more的閉包被返回。當你把這些閉包應(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

責任編輯:book05 來源: Artima
相關(guān)推薦

2011-05-25 14:48:33

Javascript閉包

2024-01-22 09:51:32

Swift閉包表達式尾隨閉包

2011-08-24 17:09:35

LUA閉包函數(shù)

2016-09-14 09:20:05

JavaScript閉包Web

2009-07-24 17:30:37

Javascript閉

2023-11-02 08:53:26

閉包Python

2021-02-21 16:21:19

JavaScript閉包前端

2009-11-16 17:04:46

Inside Scal

2009-07-21 16:58:31

Scala變量范圍

2010-06-23 10:24:42

Javascript閉

2016-09-18 20:53:16

JavaScript閉包前端

2016-11-01 09:18:33

Python閉包

2016-10-27 19:26:47

Javascript閉包

2013-05-02 09:44:57

PHP閉包

2019-11-07 21:51:18

閉包前端函數(shù)

2021-06-29 09:01:50

Swift閉包語言

2012-11-29 10:09:23

Javascript閉包

2020-09-18 14:12:28

閉包Rsut函數(shù)

2020-10-14 15:15:28

JavaScript(

2010-01-19 09:50:54

Java 7閉包
點贊
收藏

51CTO技術(shù)棧公眾號