我慢慢地将我的大脑缠绕在斯卡拉的Futures周围,并且有一层蛋糕正在进行中,我试图解开。
特定用例是sangria-graphql + akka中的DeferredResolver
。我偷了他们的演示代码,看起来像这样
Future.fromTry(Try(
friendIds map (id => CharacterRepo.humans.find(_.id == id) orElse CharacterRepo.droids.find(_.id == id))))
并添加了我自己的修改。他们在内存中查找,而我的另一个人则问:
Future.fromTry(Try(
accountIds match {
case h :: _ =>
val f = sender ? TargetedMessage(h)
val resp = Await.result(f, timeout.duration).asInstanceOf[TargetedMessage]
marshallAccount(resp.body)
case _ => throw new Exception("Not found")
}
))
这里的相关部分是我选择列表中的第一个元素,将其发送到我在其他地方的ActorRef
并等待结果。这有效。但是,我想要做的不是等待结果,而是将整个事情作为Future
Future.fromTry(Try(
accountIds match {
case h :: _ =>
sender ? TargetedMessage(h) map {
case resp:TargetedMessage => marshallAccount(resp.body)
}
case _ => throw new Exception("Not found")
}
))
这不起作用。当这被消费时,而不是类型Account
(函数marshallAccount
的返回类型),它的类型为Promise。如果我理解正确,那是因为而不是返回类型为Future[Account]
,其类型为Future[Future[Account]]
我如何压扁这个?
答案 0 :(得分:3)
您正在查看错误的API方法。 Future.fromTry
用于创建一个立即解析的Future,这意味着该调用实际上并不是异步的。深入了解Future.fromTry
的实现,它将带您进入:
def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result)
保留的承诺基本上是已经发生的事情,所以就像Future.successful
这只是用来确保正确的返回类型或类似,它实际上并不是制作异步的方法。
返回类型为Future[Future[Something]]
的原因是因为您试图将已经返回未来的东西包装到另一个未来。
问询模式,即sender ? TargetMessage(h)
是一种询问某个演员的方式并等待结果的方式,这将返回未来。
正确的方法:
val future: Future[Account] = accountIds match {
case h :: _ => sender ? TargetedMessage(h) map (marshallAccount(_.body)
case _ => Future.failed(throw new Exception("Not found"))
}
基本上,如果要保持返回类型一致,则需要使用Future.failed
从异常中返回失败的未来。值得回顾this tutorial以了解更多有关期货以及如何使用它们编写应用程序逻辑的信息。