Scala Multiple Future 包裹在 Try
Posted
技术标签:
【中文标题】Scala Multiple Future 包裹在 Try【英文标题】:Scala Multiple Future wrapped in Try 【发布时间】:2017-08-06 05:46:35 【问题描述】:假设我有许多 akka 服务,它们都返回一个 AbcDto
类型的案例类,包裹在 Try
中。
所以我使用map
调用所有这些服务并取回List[Future[Any]]
。
现在我使用Future.sequence
将其转换为Future[List[Any]]
。
如何解开我的最终结果列表?我只想在它们都是Success
时处理它们,即使一个失败我也想抛出一个错误。
我尝试将Future[List[Any]]
映射为:
val a: List[Future[Any]]
a.map
case r: List[Success[AbcDto]] => println("hello")
但这会产生错误:
case r: List[Try[AbcDto]]
。此时给出错误:非变量类型参数scala.util.Try[AbcDto]
in type pattern List[scala.util.Try[AbcDto]]
(List[scala.util.Try[AbcDto]]
的底层)
【问题讨论】:
【参考方案1】:因为所有的 akka 服务都返回 AbcDto
wrapped 在一个尝试正确的 val a
类型应该是 List[Future[Try[AbcDto]]]
。现在可以通过Future.sequence
和 flatMap 操作的组合来检查服务中的任何故障,如下所示,可以实现所需的结果。
val a: List[Future[Try[AbcDto]]] = ...
val result: Future[List[AbcDto]] = Future.sequence(a) flatMap
case r: List[Try[AbcDto]] @unchecked if r.find(!_.isSuccess).isDefined => Future.failed(new RuntimeException("not all results are successful"))
case r => Future.successful(r.collect( case Success(x) => x))
【讨论】:
是的,但我使用未来序列将 List[Future[Try[AbcDto]]] 转换为 Future[List[Try[AbcDto]]] @Sidhant 我已经更新了答案。请看一下 案例 r:列表[Try[AbcDto]]。此时它给出错误:类型模式 List[scala.util.Try[AbcDto]] 中的非变量类型参数 scala.util.Try[AbcDto](List[scala.util.Try[AbcDto]] 的底层) 实际上在您的代码类型中 a 是 :List[Future[Any]]Future[Try[_]]
堆叠很少有意义,宁愿使用Future.fromTry
进行扁平化【参考方案2】:
Future[A]
和 Try[A]
在演员上下文中是如此相似,以至于我认为没有必要从这些演员那里返回 Try[A]
。如果成功,您只需返回A
,这将是ask
ing 一侧的Future[A]
,一个List
,您可以在其中sequence
并获得Future[List[A]]
,如果发生单个故障,将包含第一个遇到的异常。这似乎正是您所要求的。
要将参与者的失败传达给ask
er,您应该发送akka.actor.Status.Failure
和Throwable
的相关实例。
附:关于使用 try-catch
是非惯用 Scala 的评论。它实际上是。以下是Try
创建的实现方式:
object Try
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch
case NonFatal(e) => Failure(e)
如您所见,它在内部使用try-catch
。如果 Scala 标准库的作者对此感到满意,那么您也应该如此。 :)
【讨论】:
所以你说我应该把我的演员代码放在 try catch 块中。如果没有异常发件人!结果。但是如果发生异常我应该使用 akka.actor.Status.Failure 以便询问接收器不会超时? 是的,我就是这个意思。 但为此我需要将我的代码放在 try catch 块中。这有点反scala吧? 一点也不。如果需要处理异常,请使用 try-catch。看看Try
本身是如何实现的。或者您仍然可以通过Try
捕获异常,但立即通过Future.fromTry
将其转换为Future
。【参考方案3】:
如果我理解正确(你的问题类型有点混乱),
您从val responseFutures: List[Future[Any]]
开始,转换后您有一个val responsesFuture: Future[List[Any]]
。流氓的答案是正确的,但它可以使用一些澄清:
您的编译器错误是由于Success
不是类,而是object
的提取器unapply
用于Try
。因此,您不能以这种方式在类型提取中使用 in。
所以像case r: List[Try[AbcDto]] if r.forall(_.isSuccess) => println("hello")
这样的东西应该可以编译。但是,当AbcDto
被擦除时,您将收到有关擦除的编译器警告。因此@unchecked
。
更新
类型擦除意味着,编译器无法在编译时检查模式匹配中的类型参数类型。在您的情况下,所有编译都知道您的输入类型是Future[List[Try[Any]]]
。
所以
future.map
case _: List[Try[AbcDto]] => ???
将导致编译器警告,因为编译器只能看到。
future.map
case _: List[Try[_]] => ???
@unchecked
注释只是抑制了相应的编译器警告。
最后,在上面的模式匹配中,您只需将传入的任何内容转换为 Try[AbcDto]
,而没有任何编译时类型安全。
【讨论】:
AbcDto被擦除是什么意思?什么是未检查的? @Sidhant 用简短的解释更新了我的答案。有关更多信息,请参阅 scala 文档。以上是关于Scala Multiple Future 包裹在 Try的主要内容,如果未能解决你的问题,请参考以下文章
在 Scala 中查找两个 Future[Int] 之间的区别
scala 报错 Multiple 'scala-library*.jar'