尝试中包含Scala多重未来

 2021-04-27 

Scala Multiple Future wrapped in Try

假设我有很多akka服务,它们都返回package在Try中的类型为AbcDto的案例类。

因此,我使用map调用了所有这些服务,并获取了List[Future[Any]]

现在,我使用Future.sequence将其转换为Future[List[Any]]

如何解开最终结果列表?我只想在所有它们都是Success时处理它们,即使一个失败我也要抛出一个错误。

我尝试将Future[List[Any]]映射为:

1
2
3
4
val a: List[Future[Any]]
a.map {
    case r: List[Success[AbcDto]] => println("hello")
}

但是这会导致错误:
case r: List[Try[AbcDto]]。在这一点上,它给出了错误:类型模式List[scala.util.Try[AbcDto]](List[scala.util.Try[AbcDto]]的基础)中的非变量类型参数scala.util.Try[AbcDto]


actor上下文中的

Future[A]Try[A]非常相似,以至于我认为没有必要从这些actor中返回Try[A]。您只需在成功的情况下返回A,它在ask侧将是Future[A],您可以在List中获得sequence并获得Future[List[A]],在单次失败的情况下,将包含第一个遇到的异常。这似乎正是您要的。

要将失败因素从actor传达给ask er,应将akka.actor.Status.Failure与相关的Throwable实例一起发送。

P.S。关于使用try-catch是非惯用Scala的评论。确实是。这是实现Try创建的方式:

1
2
3
4
5
6
7
8
9
10
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标准库作者对此表示满意,那么您也应该这样做。 :)


因为所有akka服务都返回package在Try中的AbcDtoval a的正确类型应为List[Future[Try[AbcDto]]]。现在,通过组合Future.sequence和flatMap操作来检查服务中的任何失败,可以实现所需的结果,如下所示。

1
2
3
4
5
6
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}))
}


如果我对您的理解正确(问题的类型有些混乱),

val responseFutures: List[Future[Any]]开头,转换后为val responsesFuture: Future[List[Any]]。流氓的答案是正确的,但是可以使用一些澄清:

您的编译器错误是由Success不是类,而是针对Try的带有unapply的提取器object引起的。因此,您不能以这种方式用于类型提取。

因此应编译类似case r: List[Try[AbcDto]] if r.forall(_.isSuccess) => println("hello")的内容。但是,由于AbcDto被擦除,您将收到有关擦除的编译器警告。因此@unchecked

更新

类型擦除意味着,编译器无法在编译时检查模式匹配中的类型参数类型。在您的情况下,您输入类型的所有编译已知为Future[List[Try[Any]]]

所以

1
2
3
future.map {
  case _: List[Try[AbcDto]] => ???
}

将导致编译器警告,因为编译器只能看到。

1
2
3
future.map {
  case _: List[Try[_]] => ???
}

@unchecked注释仅禁止显示相应的编译器警告。

最后,在上面的模式匹配中,您只是对Try[AbcDto]中出现的内容进行了强制转换,而没有任何编译时类型的安全性。