Что-то подобное - хорошая идея, но я бы сделал это методом:
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
с.)