1. 程式人生 > >Scala學習筆記——(Loan Pattern)借貸模式

Scala學習筆記——(Loan Pattern)借貸模式

Scala中的Loan Pattern

 資源回收是計算機工程實踐中一項重要的實現模式。對於具有GC的程式設計語言,它僅僅實現了記憶體資源的自動回收,而對於諸如檔案IO,資料庫連線,Socket連線等資源需要程式設計師自行實現資源的回收。
 該問題可以形式化地描述為:給定一個資源R,並將資源傳遞給使用者空間,並回調演算法f: R => T;當過程結束時資源自動釋放。

- Input: Given resource: R
- OutputT
- AlgorithmCall 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語句。