如何确保Scala中的for-comprehension中的资源被关闭

Asg*_*Eir 4 scala

如何在Scala中进行for-understandingnce中最好地处理带有副作用的函数?

我有一个理解,通过调用函数f1创建一种资源(x)开始.这个资源有一个close -method需要在结束时调用,但是如果for-comprehension以某种方式失败(除非.

所以我们有类似的东西:

import scala.util.{Try,Success,Failure}

trait Resource {
  def close() : Unit
}

// Opens some resource and returns it as Success or returns Failure
def f1 : Try[Resource] = ...
def f2 : Try[Resource] = ...

val res = for {
  x <- f1
  y <- f2
} yield {
  (x,y)
}
Run Code Online (Sandbox Code Playgroud)

我应该在哪里调用close方法?我可以在for-comprehension结束时将其称为最后一个语句(z < - x.close),在yield-part中,或在for-comprehension之后(res._1.close).它们都不能确保在发生错误时调用close(例如,如果f2失败).或者,我可以分开

x <- f1 
Run Code Online (Sandbox Code Playgroud)

出于这样的理解:

val res = f1
res match {
  case Success(x) => {
    for {
      y <- f2
    }
    x.close
  }

  case Failure(e) => ...       
:
Run Code Online (Sandbox Code Playgroud)

这将确保调用close但代码不是很好.难道没有更聪明,更干净的方法来实现同样的目标吗?

Ole*_*nko 7

当我遇到这样的问题时,我决定两种可能性:

  1. 使用Scala ARM
  2. 我自己实施贷款模式(链接是易变的,可能会死)

在大多数情况下,我更喜欢自己实现以避免额外的依赖 这是贷款模式的代码:

def using[A](r : Resource)(f : Resource => A) : A =
    try {
        f(r)
    } finally {
        r.close()
    }
Run Code Online (Sandbox Code Playgroud)

用法:

using(getResource())(r =>
    useResource(r)
)
Run Code Online (Sandbox Code Playgroud)

由于您需要2个资源,因此需要使用此模式两次:

using(getResource1())(r1 =>
    using(getResource2())(r2 =>
        doYourWork(r1, r2)))
Run Code Online (Sandbox Code Playgroud)

您还可以查看以下答案: