Essential Scala: Loan Pattern

资源自动回收是计算机工程实践中一项重要的实现模式,例如:

  • C++: RAII技术
  • Java7以后:try-with-resources技术

本文通过using的抽象控制,透视Scala在这个领域的设计技术。

借贷模式: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,并将资源传递给用户空间,并回调算法f: R => T;当过程结束时资源自动释放。为此,using常常被称为「借贷模式」,是保证资源自动回收的重要机制。

鸭子编程

R <: { def close(): Unit }表明R类型必须是具有def close(): Unit方法的子类型,这是Scala支持「鸭子编程」的一种重要技术。

例如,File满足R类型的特征。

惰性求值

resource: => R是按照by-name传递,在实参传递形参过程中,并未对实参进行立即求值,而将求值推延至resource: => R的调用点。

对于本例,using(Source.fromFile(source))语句中,Source.fromFile(source)并没有马上发生调用传递给形参,而将求值推延至source = Some(resource)语句,调用Some.apply方法时。

控制抽象

使得using形如内置于语言的控制结构,其行为类似于if, while一样。

def read: String = using(fromFile(source)) { 
  _.getLines.mkString(lineSeparator) 
}

for推导式

finally关闭资源时,使用for推导式过滤掉None。也就是说,如下三种形式是等价的。

  • 过滤掉None,并自动提取Option中的元素
for (s <- source)
  s.close
  • 使用if,但需要从Some中手动get
if (source != None)
  source.get.close

你可能感兴趣的:(Essential Scala: Loan Pattern)