在scala中释放IO资源而不维护可变状态
我需要使用一些Java库,它可能会在一个方法中抛出一些异常,并在另一组方法中返回错误代码。到目前为止,它导致了像在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
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创建可调用的块。然后改用实用方法。它不会使这个特定的方法变得漂亮,但至少会减少它的占用空间。这就是我实际上正在做的——将事务管理和游标提取到带有隐式错误生成器的实用方法中。然而,它仍然看起来。。。奇怪的