我的代码中有一个场景,我需要根据包含特定值的成功结果使Future
失败。我可以通过flatMap
使这项工作正常,但我想知道是否有更简洁的方法来完成这项工作。首先,一个非常简单的例子:
import concurrent._
case class Result(successful:Boolean)
object FutureTest {
def main(args: Array[String]) {
import ExecutionContext.Implicits._
val f = Future{Result(false)}.flatMap{ result =>
result match{
case Result(false) => Promise.failed(new Exception("The call failed!!")).future
case _ => Promise.successful(result).future
}
}
f onFailure{
case x => println(x.getMessage())
}
}
}
因此,在我的示例中,如果返回的Future
的成功指标值为Result
,我希望false
失败。正如我所提到的,我可以使用flatMap
使这项工作正常,但我希望消除的代码行是:
case _ => Promise.successful(result).future
这句话似乎没必要。我想要的行为是能够定义条件,如果它的计算结果为true,那么允许我像我一样返回不同的Future
,但如果不是这样,那就按照原样保留原样(有点像PartialFunction
语义。有没有办法做到这一点,我只是没有看到?我看过collect
和transform
那些似乎不是正确适合。
修改
在从@Rex Kerr和@ senia获得map
建议后,我创建了一个PimpedFuture
并进行了隐式转换,以便对代码进行调整:
class PimpedFuture[T](f:Future[T])(implicit ex:ExecutionContext){
def failWhen(pf:PartialFunction[T,Throwable]):Future[T] = {
f map{
case x if (pf.isDefinedAt(x)) => throw pf(x)
case x => x
}
}
}
隐含的
implicit def futToPimpedFut[T](fut:Future[T])(implicit ec:ExecutionContext):PimpedFuture[T] = new PimpedFuture(fut)
新的处理代码:
val f = Future{ Result(false) } failWhen {
case Result(false) => new Exception("The call failed!!")
}
我认为这仍然有点干净,同时仍然使用建议来使用map
。
答案 0 :(得分:6)
您可以使用map
:
val f = Future{ Result(false) } map {
case Result(false) => throw new Exception("The call failed!!")
case x => x
}
但你仍然需要明确提到你正在传递身份。
请注意,should not在这种情况下使用andThen
。 andThen
用于副作用,而不是用于更改结果(与同名的Function1
方法不同)。
答案 1 :(得分:0)
还有一个不同的解决方案(没有像@cmbaxter提到的堆栈跟踪副作用)
val prom = Promise[Int]()
val f = future {
1
}
f onComplete {
case Success(i) if i < 5 => prom.failure(new RuntimeException("_ < 5"))
case Success(x) => prom.success(x)
}
prom.future onComplete {
case Success(s) => println(s"We cool '$s'")
case Failure(th) => println(s"All failed, ${th.getMessage}")
}
答案 2 :(得分:0)
最干净的解决方案是调用filter
方法,如评论中提到的@senia。
Future { Result(false) }.filter(_.successful) // throws NoSuchElementException
如果要使用其他异常类型,可以将呼叫与recoverWith
链接:
Future { Result(false) }.filter(_.successful).recoverWith {
case _: NoSuchElementException => Future.failed(new Exception("The call failed!!"))
}