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标准库作者对此表示满意,那么您也应该这样做。 :)
-
所以你说我应该把我的演员代码放在try catch块中。如果没有异常发件人!结果。但是,如果发生异常,我应该使用akka.actor.Status.Failure,以便请求接收方不会超时?
-
是的,这就是我的意思。
-
但是为此,我需要将我的代码放在try catch块中。多数民众赞成在一点反scala吧?
-
一点也不。如果需要处理异常,请使用try-catch。看看Try本身是如何实现的。或者,您仍然可以通过Try捕获异常,但立即通过Future.fromTry将其转换为Future。
因为所有akka服务都返回package在Try中的AbcDto,val 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 }))
} |
- 是的,但是我使用了Future序列将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展平
如果我对您的理解正确(问题的类型有些混乱),
以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]中出现的内容进行了强制转换,而没有任何编译时类型的安全性。
-
AbcDto被删除是什么意思?那到底是什么?
-
@Sidhant用简短说明更新了我的答案。请参阅scala文档,以获取更多信息。