Сопоставьте будущее как успеха, так и неудачи
У меня есть Future [T], и я хочу сопоставить результат как с успехом, так и с отказом.
Например, что-то вроде
val future = ... // Future[T]
val mapped = future.mapAll {
case Success(a) => "OK"
case Failure(e) => "KO"
}
Если я использую map
или flatmap
, он отображает только фьючерсы на успех. Если я использую recover
, он отображает только несостоявшиеся фьючерсы. onComplete
выполняет обратный вызов, но не возвращает измененное будущее. Transform
будет работать, но он принимает 2 функции, а не частичную функцию, поэтому немного уродливее.
Я знаю, что могу создать новый Promise
, и завершить это с помощью onComplete
или onSuccess
/onFailure
, но я надеялся, что что-то у меня пропало, что позволит мне сделать это с помощью одиночный PF.
Ответы
Ответ 1
Изменить 2017-09-18: Начиная с Scala 2.12, существует метод transform
, который принимает Try[T] => Try[S]
. Таким образом, вы можете написать
val future = ... // Future[T]
val mapped = future.transform {
case Success(_) => Success("OK")
case Failure(_) => Success("KO")
}
Для 2.11.x ниже применяется следующее:
AFAIK, вы не можете сделать это напрямую с помощью одного PF. И transform
преобразует Throwable = > Throwable, так что это тоже вам не поможет. Ближе всего вы можете выйти из окна:
val mapped: Future[String] = future.map(_ => "OK").recover(_ => "KO")
Тем не менее, реализация вашего mapAll тривиальна:
implicit class RichFuture[T](f: Future[T]) {
def mapAll[U](pf: PartialFunction[Try[T], U]): Future[U] = {
val p = Promise[U]()
f.onComplete(r => p.complete(Try(pf(r))))
p.future
}
}
Ответ 2
На первом этапе вы можете сделать что-то вроде:
import scala.util.{Try,Success,Failure}
val g = future.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map {
case Success(s) => ...
case Failure(t) => ...
}
где T
- тип будущего результата. Затем вы можете использовать неявное преобразование, чтобы добавить эту структуру в свойство Future
как новый метод:
implicit class MyRichFuture[T]( fut: Future[T] ) {
def mapAll[U]( f: PartialFunction[Try[T],U] )( implicit ec: ExecutionContext ): Future[U] =
fut.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map( f )
}
который реализует синтаксис, который вы ищете:
val future = Future{ 2 / 0 }
future.mapAll {
case Success(i) => i + 0.5
case Failure(_) => 0.0
}
Ответ 3
Оба варианта карты и flatMap:
implicit class FutureExtensions[T](f: Future[T]) {
def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
val p = Promise[Target]()
f.onComplete { r => p success m(r) }(ec)
promise.future
}
def flatMapAll[Target](m: Try[T] => Future[Target])(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => m(r).onComplete { z => promise complete z }(ec) }(ec)
promise.future
}
}
Ответ 4
Поскольку Scala 2.12, вы можете использовать transform
для сопоставления обоих случаев:
future.transform {
case Success(_) => Try("OK")
case Failure(_) => Try("KO")
}
У вас также есть transformWith
, если вы предпочитаете использовать Future
вместо Try
. Подробнее см. .