我一直在尝试找到一种很好的方法,将Scala中的Try链与后续资源清理结合起来。我最终看到的是这样的(由scalaz提供支持)
for {
x <- \/.fromTryCatchNonFatal(...)
y <- \/.fromTryCatchNonFatal(...).leftMap( /* clean up x */ )
z <- \/.fromTryCatchNonFatal(...).leftMap( /* clean up x and y */ )
// clean up everything
} yield (...)
这种方法的问题是,如果您有3个以上的Try块,可能会发生某些情况下的清理工作。更不用说它看起来笨重和丑陋。
所以我想出了一个Scala的包装器,尝试使用scalaz提供的State和Either单子。
我最终看到的是这样的:
val try = for {
a <- Try(/* no resources allocated here */).noRes
c <- Try(20).res { x => /** create DB connection */ }.res(/* release DB connection */)
} yield (..)
val result: Throwable \/ T = try.safeEval
通过这种方式从您的工作中获得的好处是,您可以确保在发生异常情况和成功计算的情况下都将释放所有资源。
此代码尚未准备好用于生产,肯定需要一些改进。
您如何看待,您认为这种方法可行吗? 您会建议以不同的方式做同一件事吗?
答案 0 :(得分:2)
这正是Bracket
的用途。它以cats-effect定义,是MonadError
的扩展,可为您提供安全的资源处理。例如:
val foo =
IO.pure(42).bracket(int => /* use resource */ ???)(_ => /* release resource */ ???)