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

时间:2012-01-14 22:11:00

标签: scala

是否有更好的方法来确保资源得到正确发布 - 更好的方法来编写以下代码?

        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()
          }

        }

3 个答案:

答案 0 :(得分:20)

这样的事情是个好主意,但我会把它变成一种方法:

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
  }
}

(请注意,我们只抓一次;如果你真的想要在一个案例中打印一条消息而不是另一个案例,那么你必须像你一样抓住这两个消息)。 (另请注意,我只捕获异常;捕获Error通常也是不明智的,因为它几乎不可能从中恢复。)方法的使用方式如下:

cleanly(new FileOutputStream(path))(_.close){ fos =>
  Iterator.continually(in.read).takeWhile(_ != -1).foreach(fos.write)
}

因为它返回一个值,如果它在这里成功(你可以忽略它),你将获得Some(())


编辑:为了使它更通用,我真的让它返回Either,所以你得到了例外。像这样:

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,一切都没问题。如果您获得Left,则可以选择异常。如果您不关心异常,可以使用.right.toOption将其映射到一个选项中,或者只使用.right.map或其他任何内容来操作正确的结果(如果它在那里) Option)。 (模式匹配是处理Either的有用方法。)

答案 1 :(得分:17)

查看Scala-ARM

  

该项目旨在成为scala库中自动资源管理的Scala Incubator项目......

     

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

答案 2 :(得分:0)

或者你也可以使用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

此处有更多信息:https://github.com/choppythelumberjack/tryclose

(只需确保导入tryclose._tryclose.JavaImplicits._