Scala學習筆記——(Loan Pattern)借貸模式
阿新 • • 發佈:2019-01-02
Scala中的Loan Pattern
資源回收是計算機工程實踐中一項重要的實現模式。對於具有GC的程式設計語言,它僅僅實現了記憶體資源的自動回收,而對於諸如檔案IO,資料庫連線,Socket連線等資源需要程式設計師自行實現資源的回收。
該問題可以形式化地描述為:給定一個資源R,並將資源傳遞給使用者空間,並回調演算法f: R => T;
當過程結束時資源自動釋放。
- Input: Given resource: R
- Output:T
- Algorithm:Call back to user namespace: f: R => T, and make sure resource be closed on done.
因此,該實現模式也常常被稱為「借貸模式」,是保證資源自動回收的重要機制。本文通過using的抽象控制,透視Scala在這個領域的設計技術,以便鞏固「按名傳遞」技術的應用。
簡單實現
/**
* 名字呼叫和值呼叫
*/
object manage {
def apply[R <: {def close() : Unit}, T](resource: => R)(f: R => T) = {
var res: Option[R] = None
try {
res = Some(resource)
f(res.get)
} catch {
case NonFatal(ex) => println(s"Non fatal exception! $ex" )
} finally {
if(res != None) {
println(s"Closing resource ...")
res.get.close()
}
}
}
}
等價於
object using {
type Closeable = { def close(): Unit }
def apply[T <: Closeable, R](resource: => T)(f: T => R): R = {
var source = null.asInstanceOf[T]
try {
source = resource
f(source)
} finally {
if (source != null) source.close
}
}
}
統計一個檔案的行數呼叫如下:
object TryCatchARM extends App{
def countLines(fileName:String): Unit = {
println("count file lines")
using(Source.fromFile(fileName)) { source =>
val size = source.getLines.size
println(s"file $fileName has $size lines")
if(size > 20) throw new RuntimeException("Big file")
}
}
args foreach(arg => countLines(arg))
}
R <: {def close() : Unit}
等價於type Closeable = { def close(): Unit }
定義了一個Closeable
的類型別名,使得T必須是具有close方法的子型別,這是Scala支援「鴨子程式設計」的一種重要技術。例如,File滿足T型別的特徵,它具有close方法。
這樣,不管是什麼物件,只要它擁有一個close():Unit的函式,都可以在這裡使用,並且這個close最後將被自動呼叫。
惰性求值
resource: => T是按照by-name傳遞,在實參傳遞形參過程中,並未對實參進行立即求值,而將求值推延至resource: =>
T的呼叫點。
對於本例,using(Source.fromFile(source))
語句中,Source.fromFile(source)
並沒有馬上發生呼叫並傳遞給形參,而將求值推延至source = resource語句。