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



我在使用 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

在您的示例中,当您访问已关闭的流时,通常会引发异常。存在 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)

像其他 monads 一样,Try 为您提供了编译时保证,不会直接访问包装的值:您必须编写高阶函数才能对其值进行操作。

最新更新