Подтвердить что ты не робот

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

        }
4b9b3361

Ответ 1

Что-то вроде этого - хорошая идея, но я бы сделал это методом:

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

(обратите внимание, что мы поймаем только один раз, если вы действительно хотите, чтобы сообщение было напечатано в одном случае, а не другом, тогда вам нужно поймать обоих, как и вы). (Также обратите внимание, что я занимаюсь только исключениями; catching 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 s.)

Ответ 2

Посмотрите Scala-ARM

Этот проект предназначен для проекта Scala Incubator для автоматического управления ресурсами в библиотеке Scala...

... Библиотека Scala ARM позволяет пользователям открывать закрытие ресурсов в блоках кода с помощью "управляемого" метода. "Управляемый" метод по существу принимает аргумент "всего, что имеет метод close или dispose" и создает новый объект ManagedResource.

Ответ 3

В качестве альтернативы вы можете сделать это с помощью 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._)