資源自動回收是計算機工程實踐中一項重要的實現(xiàn)模式,例如:
-
C++:RAII技術(shù) -
Java7以后:try-with-resources技術(shù)
本文通過using的抽象控制,透視Scala在這個領(lǐng)域的設(shè)計技術(shù)。
借貸模式:using
import scala.language.reflectiveCalls
object using {
def apply[R <: { def close(): Unit }, T](resource: => R)(f: R => T): T = {
var source: Option[R] = None
try {
source = Some(resource)
f(source.get)
} finally {
for (s <- source)
s.close
}
}
}
形式化
拋開using.apply復雜的類型修飾符,其算法可形式化為:
Input: Given resource: R
Output:T
Algorithm:Call back to user namespace: f: R => T, and make sure resource be closed on done.
給定一個資源R,并將資源傳遞給用戶空間,并回調(diào)算法f: R => T;當過程結(jié)束時資源自動釋放。為此,using常常被稱為「借貸模式」,是保證資源自動回收的重要機制。
鴨子編程
R <: { def close(): Unit }表明R類型必須是具有def close(): Unit方法的子類型,這是Scala支持「鴨子編程」的一種重要技術(shù)。
例如,File滿足R類型的特征。
惰性求值
resource: => R是按照by-name傳遞,在實參傳遞形參過程中,并未對實參進行立即求值,而將求值推延至resource: => R的調(diào)用點。
對于本例,using(Source.fromFile(source))語句中,Source.fromFile(source)并沒有馬上發(fā)生調(diào)用傳遞給形參,而將求值推延至source = Some(resource)語句,調(diào)用Some.apply方法時。
控制抽象
使得using形如內(nèi)置于語言的控制結(jié)構(gòu),其行為類似于if, while一樣。
def read: String = using(fromFile(source)) {
_.getLines.mkString(lineSeparator)
}
for推導式
在finally關(guān)閉資源時,使用for推導式過濾掉None。也就是說,如下三種形式是等價的。
- 過濾掉
None,并自動提取Option中的元素
for (s <- source)
s.close
- 使用
if,但需要從Some中手動get
if (source != None)
source.get.close