Scala最终阻止关闭/刷新资源

Scala最终阻止关闭/刷新资源,scala,Scala,有没有更好的方法来确保资源被正确释放?有没有更好的方法来编写以下代码 val out: Option[FileOutputStream] = try { Option(new FileOutputStream(path)) } catch { case _ => None } if (out.isDefined) { try { Iter

有没有更好的方法来确保资源被正确释放?有没有更好的方法来编写以下代码

        val out: Option[FileOutputStream] = try {
          Option(new FileOutputStream(path))
        } catch {
          case _ => None
        }


        if (out.isDefined) {

          try {
            Iterator.continually(in.read).takeWhile(-1 != _).foreach(out.get.write)
          } catch {
            case e => println(e.getMessage)
          } finally {
            in.close
            out.get.flush()
            out.get.close()
          }

        }
看看

本项目旨在成为Scala图书馆中用于自动资源管理的Scala孵化器项目

。。。Scala ARM库允许用户使用“托管”方法确保代码块内资源的打开和关闭。“managed”方法本质上接受一个参数“任何具有close或dispose方法的对象”,并构造一个新的ManagedResource对象


这是个好主意,但我会把它作为一种方法:

def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Option[B] = {
  try {
    val r = resource
    try { Some(code(r)) }
    finally { cleanup(r) }
  } catch {
    case e: Exception => None
  }
}
(请注意,我们只捕获一次;如果您确实希望在一种情况下打印消息,而不是在另一种情况下打印消息,那么您必须像以前一样捕获这两种情况)。(还要注意,我只捕获异常;捕获
错误
通常也是不明智的,因为几乎不可能从中恢复。)该方法的使用方式如下:

cleanly(new FileOutputStream(path))(_.close){ fos =>
  Iterator.continually(in.read).takeWhile(_ != -1).foreach(fos.write)
}
由于它返回一个值,如果它在这里成功,您将得到一个
Some(())
(您可以忽略)


编辑:为了使它更通用,我真的希望它返回一个
,这样您就得到了异常。像这样:

def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Either[Exception,B] = {
  try {
    val r = resource
    try { Right(code(r)) } finally { cleanup(r) }
  }
  catch { case e: Exception => Left(e) }
}

现在如果你的
正确
,一切都会好起来。如果您得到一个
,您可以选择您的异常。如果您不关心异常,可以使用
.right.toOption
将其映射到一个选项中,或者仅使用
.right.map
或其他任何工具,仅当存在正确的结果时才对其进行操作(就像使用
option
)。(模式匹配是处理
s]的一种有用方法。

或者,您可以使用Choppy的Lazy TryClose monad来实现这一点

val output = for {
  fin   <- TryClose(in)
  fout  <- TryClose.wrapWithCloser(new FileOutputStream(path))(out => {out.flush(); out.close();})
} yield wrap(Iterator.continually(fin.read).takeWhile(-1 != _).foreach(fout.get.write))

// Then execute it like this:
output.resolve
val输出=for{

fin为什么要将资源分配给r?为什么不直接使用它。您是否认为这种简化有任何错误,只需删除一次尝试。
def cleanly[ab]:或者[Exception,B]={try{Right(code(resource))}catch{case e e:Exception=>Left(e)}最后{resource.close}
@rvange-生成资源可能会导致异常,因此您需要按名称调用。资源可能不是
java.io.Closeable
,因此允许用户指定的清理更为通用。如果您只有
java.io.Closeable
s,并且您确定资源将无异常地创建自己,或者您需要如果不传播该异常,那么您的代码就可以了。很好,但是您不是创建了两个try块来实现相同的功能吗?资源在外部try块中创建,在内部try块中清理,如果您将内部try块重构为另一个方法,您将永远不会知道外部try方法中的情况。我缺少什么吗?C#有som吗这就像使用(val resource=…){..}一样,即使存在异常,编译器也会在存在之前自动调用dispose,但愿Scala有什么功能similar@skjagini-它在2.13中获得了一个(作为一种库方法,它仔细地阐述了上述模式)。你知道Scala ARM的状态吗?它看起来已经死了——自5月份以来没有提交。因为我需要能够嵌套多个java.lang.AutoCloseable实例,每个实例都取决于前一个成功实例化的实例,所以我最终找到了一个对我非常有用的模式。我在类似的StackOver上写下了它作为答案流动问题: