Essential Scala: Loan Pattern

作者: 刘光聪 | 来源:发表于2016-07-31 10:55 被阅读558次

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

    • 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

        本文链接:https://www.haomeiwen.com/subject/ivwtsttx.html