在scala中释放IO资源而不维护可变状态

在scala中释放IO资源而不维护可变状态,scala,immutability,resource-management,Scala,Immutability,Resource Management,我需要使用一些Java库,它可能会在一个方法中抛出一些异常,并在另一组方法中返回错误代码。到目前为止,它导致了像 val txn = mgr.prepareTransaction() val accessRecord = txn.readByQuery(...) var state : Either[MyError, Result] = null // try { // do something here val result = txn.runCodeWithin(new Callab

我需要使用一些Java库,它可能会在一个方法中抛出一些异常,并在另一组方法中返回错误代码。到目前为止,它导致了像

val txn = mgr.prepareTransaction()
val accessRecord = txn.readByQuery(...)
var state : Either[MyError, Result] = null //
try {
  // do something here
  val result = txn.runCodeWithin(new Callable[Result]() {...})
  if (result == -1) {
    state = Left(CanNotReadRecord)
  } else {
    state = Right(txn.getCachedRecord())
  }
} catch {
  case e: Exception => state = Left(GeneralError(e))
} finally {
  state match {
    case Right(_) => txn.commit();
    case _        => txn.rollback();
  }
}
我最感兴趣的是将状态作为var去掉,以及在finally块中检查状态的能力。请注意。

自动资源管理库以一种完全密封的方式优雅地处理所有这类事情

看看吧。

Scala 2.10引入了Try类,它是对[Throwable,Result]用例的更具功能的替代。它包含了所有常用的单子运算,有助于理解的东西,还有其他一些有用的方法

下面是代码的一个可能的重新实现,使用Try,并用CanNotReadRecordException替换CanNotReadRecord。它应该在功能上等同于您的示例,但替换除外

def txResults(txn: Transaction): Try[Record] = for {
    result <- Try{ txn.runCodeWithin(...) }
    checked <- result match {
        case -1 => Failure( new CanNotReadRecordException )
        case _ => Success( txn.getCachedRecord )
    }
} yield checked

txResults(txn) match {
    case Success(record) => txn.commit()
    case Failure(e) => txn.rollback() //and maybe handle `e`
}

尽管我认为在这个特定的示例中使用库仍然是非常重要的,因为根据结果,您有一个错误或记录,因此这将产生一个[MyError,result]。因此,使用resource.other将产生一个必须组合为[MyError,Result]的非此即彼的非此即彼的[Seq[Exception],非此即彼的[MyError,Result]]方法。如果您的整个模式都相同,那么您可以将其丑陋之处考虑到一个实用程序方法中,该方法包含3个参数mgr,readByQuery的arg和一个用于为RunCodeIn创建可调用的块。然后改用实用方法。它不会使这个特定的方法变得漂亮,但至少会减少它的占用空间。这就是我实际上正在做的——将事务管理和游标提取到带有隐式错误生成器的实用方法中。然而,它仍然看起来。。。奇怪的