将Akka的未来[A]转换为未来[要么[例外,A]]

时间:2013-01-05 04:50:59

标签: scala akka future scala-2.10 scala-2.9

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的答案感兴趣。

3 个答案:

答案 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