资源自动回收是计算机工程实践中一项重要的实现模式,例如:
-
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
网友评论