Скала окончательно блокирует закрытие / сброс ресурса - PullRequest
21 голосов
/ 15 января 2012

Есть ли лучший способ обеспечить правильное освобождение ресурсов - лучший способ написать следующий код?

        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 ]

20 голосов
/ 15 января 2012

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

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 с.)

17 голосов
/ 15 января 2012

Взгляните на Scala-ARM

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

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

0 голосов
/ 17 января 2018

В качестве альтернативы вы можете сделать это с монадой Choppy's Lazy TryClose.

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._)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...