鍍金池/ 教程/ Scala/ 函數(shù)–閉包
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達(dá)式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達(dá)式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動(dòng)態(tài)綁定
Trait 的基本概念
if 表達(dá)式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實(shí)現(xiàn)方法
try 表達(dá)式處理異常
選擇瘦接口還是胖接口設(shè)計(jì)?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進(jìn)一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實(shí)現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調(diào)用基類構(gòu)造函數(shù)
減低代碼重復(fù)
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴(kuò)展類
函數(shù)–部分應(yīng)用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實(shí)現(xiàn)可疊加的修改操作

函數(shù)–閉包

到目前為止我們介紹的函數(shù)都只引用到傳入的參數(shù),假如我們定義如下的函數(shù):

(x:Int) => x + more

這里我們引入一個(gè)自由變量 more。它不是所定義函數(shù)的參數(shù),而這個(gè)變量定義在函數(shù)外面,比如:

var more =1

那么我們有如下的結(jié)果:

scala> var more =1
more: Int = 1
scala> val addMore = (x:Int) => x + more
addMore: Int => Int = <function1>
scala> addMore (100)
res1: Int = 101

這樣定義的函數(shù)變量 addMore 成為一個(gè)“閉包”,因?yàn)樗玫胶瘮?shù)外面定義的變量,定義這個(gè)函數(shù)的過程是將這個(gè)自由變量捕獲而構(gòu)成一個(gè)封閉的函數(shù)。有意思的是,當(dāng)這個(gè)自由變量發(fā)生變化時(shí),Scala 的閉包能夠捕獲到這個(gè)變化,因此 Scala 的閉包捕獲的是變量本身而不是當(dāng)時(shí)變量的值。

比如:

scala> more =  9999
more: Int = 9999
scala> addMore ( 10)
res2: Int = 10009

同樣的,如果變量在閉包在發(fā)生變化,也會(huì)反映到函數(shù)外面定義的閉包的值。比如:

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 的值,其結(jié)果還是傳遞到閉包的外面。

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

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

當(dāng)你調(diào)用 makeIncreaser(1)時(shí),你創(chuàng)建了一個(gè)閉包,該閉包定義時(shí) more的值為 1,而調(diào)用 makeIncreaser(9999)所創(chuàng)建的閉包的 more 的值為 9999。此后你也無法修改已經(jīng)返回的閉包的 more 的值。因此 inc1 始終為加一,而 inc9999 始終為加 9999。

上一篇:類和對象 (五)下一篇:起步 Scala