3

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

1 回答 1

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它为您提供编译时保证,不会直接访问包装的值:您必须编写高阶函数才能对其值进行操作。

于 2013-10-16T10:18:11.183 回答