scala 规划成功和失败的未来

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23043679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 06:11:20  来源:igfitidea点击:

Map a Future for both Success and Failure

scalafuture

提问by monkHyman

I have a Future[T] and I want to map the result, on both success and failure.

我有一个 Future[T],我想将结果映射到成功和失败上。

Eg, something like

例如,像

val future = ... // Future[T]
val mapped = future.mapAll { 
  case Success(a) => "OK"
  case Failure(e) => "KO"
}

If I use mapor flatmap, it will only map successes futures. If I use recover, it will only map failed futures. onCompleteexecutes a callback but does not return a modified future. Transformwill work, but takes 2 functions rather than a partial function, so is a bit uglier.

如果我使用mapor flatmap,它只会映射成功的期货。如果我使用recover,它只会映射失败的期货。onComplete执行回调但不返回修改后的未来。Transform会工作,但需要 2 个函数而不是部分函数,​​所以有点难看。

I know I could make a new Promise, and complete that with onCompleteor onSuccess/onFailure, but I was hoping there was something I was missing that would allow me to do the above with a single PF.

我知道我可以制作一个新的Promise,并用onCompleteor onSuccess/完成它onFailure,但我希望有一些我遗漏的东西可以让我用单个 PF 完成上述操作。

回答by espenhw

Edit 2017-09-18: As of Scala 2.12, there is a transformmethod that takes a Try[T] => Try[S]. So you can write

编辑 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")
}

For 2.11.x, the below still applies:

对于 2.11.x,以下仍然适用:

AFAIK, you can't do this directly with a single PF. And transformtransforms Throwable => Throwable, so that won't help you either. The closest you can get out of the box:

AFAIK,您不能直接使用单个 PF 执行此操作。并transform转换 Throwable => Throwable,所以这也无济于事。您可以开箱即用的最接近的:

val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}

That said, implementing your mapAll is trivial:

也就是说,实现你的 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
  }
}

回答by nmat

Since Scala 2.12you can use transformto map both cases:

Scala 2.12 开始,您可以使用transform映射两种情况:

future.transform {
      case Success(_) => Try("OK")
      case Failure(_) => Try("KO")
}

You also have transformWithif you prefer to use a Futureinstead of a Try. Check the documentationfor details.

transformWith如果您更喜欢使用 aFuture而不是 a ,您也可以使用Try。查看文档了解详细信息。

回答by paradigmatic

In a first step, you could do something like:

第一步,您可以执行以下操作:

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) => ...
}

where Tis the type of the future result. Then you can use an implicit conversion to add this structure the Futuretrait as a new method:

哪里T是未来结果的类型。然后您可以使用隐式转换将此结构添加到Futuretrait 作为新方法:

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

which implements the syntax your are looking for:

它实现了您正在寻找的语法:

val future = Future{ 2 / 0 }
future.mapAll {
  case Success(i) => i + 0.5
  case Failure(_) => 0.0
}

回答by sungiant

Both map and flatMap variants:

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