Scala閉包


假如我們定義如下的函數:

(x:Int) => x + more

這里我們引入一個自由變量more.它不是所定義函數的參數,而這個變量定義在函數外面,比如:

var more =1

那么我們有如下的結果:

scala> var more =1
more: Int = 1

scala> val addMore = (x:Int) => x + more
addMore: Int => Int = <function1>

scala> addMore (100)
res1: Int = 101

這樣定義的函數變量addMore 成為一個“閉包”,因為它引用到函數外面定義的變量,定義這個函數的過程是將這個自由變量捕獲而構成一個封閉的函數。有意思的是,當這個自由變量發生變化時,Scala的閉包能夠捕獲到這個變化,因此Scala的閉包捕獲的是變量本身而不是當時變量的值。

比如:

scala> more =  9999
more: Int = 9999

scala> addMore ( 10)
res2: Int = 10009

同樣的,如果變量在閉包在發生變化,也會反映到函數外面定義的閉包的值。比如:

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
res4: Int = -11

可以看到在閉包中修改sum的值,其結果還是傳遞到閉包的外面。

如果一個閉包所訪問的變量有幾個不同的版本,比如一個閉包使用了一個函數的局部變量(參數),然后這個函數調用很多次,那么所定義的閉包應該使用所引用的局部變量的哪個版本呢? 簡單的說,該閉包定義所引用的變量為定義該閉包時變量的值,也就是定義閉包時相當於保存了當時程序狀態的一個快照。比如我們定義下面一個函數閉包:

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

scala> val inc1=makeIncreaser(1)
inc1: Int => Int = <function1>

scala> val inc9999=makeIncreaser(9999)
inc9999: Int => Int = <function1>

scala> inc1(10)
res5: Int = 11

scala> inc9999(10)
res6: Int = 10009

當你調用makeIncreaser(1)時,你創建了一個閉包,該閉包定義時more的值為1, 而調用makeIncreaser(9999)所創建的閉包的more的值為9999。此后你也無法修改已經返回的閉包的more的值。因此inc1始終為加一,而inc9999始終為加9999.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM