Akka(或Scala 2.10中的标准库)中是否有方法将可能失败的Future[A]
转换为Future[Either[Exception,A]]
?我知道你可以写
f.map(Right(_)).recover {
case e:Exception => Left(e)
}
这似乎是一项普遍的任务,我想知道我是否忽略了某些东西。我对Scala 2.9 / Akka和Scala 2.10的答案感兴趣。
答案 0 :(得分:10)
缺少此方法的主要原因是它实际上没有良好的语义:静态类型Future[Either[Throwable, T]]
无法确保未来不会失败,因此类型更改通常不会获得太多。
如果您控制处理这些未来的所有代码当然是有道理的,在这种情况下,自己添加它是微不足道的(这个名称是由于我在第一杯咖啡之前发布的,可以随意更换更好的东西):
implicit class FutureOps[T](val f: Future[T]) extends AnyVal {
def lift(implicit ec: ExecutionContext): Future[Either[Throwable,T]] = {
val p = promise[Either[Throwable,T]]()
f.onComplete {
case Success(s) => p success Right(s)
case Failure(ex) => p success Left(ex)
}
p.future
}
}
它与Akka 2.0期货非常相似,因此我将这个练习留给了读者。
答案 1 :(得分:1)
这种转换的另一个版本(在标准Scala中):
@PostMapping("/foobar/{fooId}")
public Mono<Bar> fooBar(@PathVariable Integer fooId) {
Mono<Foo> fooMono = fooWebClient().get().uri("/{id}", fooId).retrieve().bodyToMono(Foo.class);
return fooMono.flatMap(foo ->
barWebClient()
.post()
.body(Mono.just(new Bar(foo.getFooStuff(), new Date())), Bar.class)
.retrieve()
.bodyToMono(Bar.class)
);
}
答案 2 :(得分:0)
我认为你无论如何都不想这样做。 Akka 2.0.5的文档显示了akka.dispatch.Future
:
abstract def onComplete[U](func: (Either[Throwable, T]) ⇒ U): Future.this.type
因此,未来可能失败的信息已经嵌入到Future[T]
的行为中。这同样适用于Scala 2.10的未来,其中未来可以作为Try[T]
完成,其目的与Either[Exception, T]
相似。
//in scala.concurrent.Future:
abstract def onComplete[U]
(func: (Try[T]) ⇒ U)(implicit executor: ExecutionContext): Unit