如何防止对象离开其封闭范围

时间:2013-10-16 09:50:20

标签: scala

我在使用PDF库时遇到了这个问题,但是在很多其他场合我会有这样的东西。

许多情况,你有一个资源(需要关闭),并且你使用这些资源来获取只有在资源是开放且没有资源的情况下才有效的对象已经发布了。

假设以下代码中的b引用仅在a打开时有效:

val a = open()
try {
  val b = a.someObject()
} finally {
  a.close()
}

现在,这段代码很好,但这段代码不是:

val b = {
  val a = open()
  try {
    a.someObject()
  } finally {
    a.close()
  }
}

使用 代码,我会引用一些资源a,而a不再打开。

理想情况下,我想要这样的事情:

// Nothing producing an instance of A yet, but just capturing the way A needs
// to be opened.
a = Safe(open()) // Safe[A]

// Just building a function that opens a and extracts b, returning a Safe[B]
val b = a.map(_.someObject()) // Safe[B]

// Shouldn't compile since B is not safe to extract without being in the scope 
// of an open A.
b.extract 

// The c variable will hold something that is able to exist outside the scope of 
// an open A.
val c = b.map(_.toString)

// So this should compile
c.extract

1 个答案:

答案 0 :(得分:2)

在您的示例中,通常在访问已关闭的流时抛出异常。存在util.Try,它完全针对此用例:

scala> import scala.util._
import scala.util._

scala> val s = Try(io.Source.fromFile("exists"))
s: scala.util.Try[scala.io.BufferedSource] = Success(non-empty iterator)

// returns a safe value
scala> s.map(_.getLines().toList)
res21: scala.util.Try[List[String]] = Success(List(hello))

scala> s.map(_.close())
res22: scala.util.Try[Unit] = Success(())

scala> val data = s.map(_.getLines().toList)
data: scala.util.Try[List[String]] = Failure(java.io.IOException: Stream Closed)

// not safe anymore, thus you won't get access to the data with map
scala> data.map(_.length)
res24: scala.util.Try[Int] = Failure(java.io.IOException: Stream Closed)

与其他monad一样,Try为您提供编译时保证,不会直接访问包装值:您必须编写更高阶函数来操作其值。