有了Futures
,有一种简单的方法可以将Seq[Future]
转换为Future[Seq]
:
Future.sequence(seqOfFutures)
我找不到与Try
类似的东西。
它可以与foldLeft
一起使用,但我真正喜欢的东西会像Try.sequence(seqOfTry)
。
是否有没有提供这种功能的原因?
这如何正确完成?
语义:
成功值列表:Success(Seq(1,2,3,4))
对于失败,有两种可能性:
拳头Failure
失败并返回。这是通过以下问题解决的:listtryt-to-trylistt-in-scala
收集所有Failures
并返回“复合”失败。
还有解决“复合”故障的解决方案吗?
答案 0 :(得分:4)
根据路易斯的建议Validated
是专为错误累积而设计的,因此请像这样考虑traverse
la.traverse(_.toEither.toValidatedNec)
lb.traverse(_.toEither.toValidatedNec)
输出
res2: cats.data.ValidatedNec[Throwable,List[Int]] = Invalid(Chain(java.lang.RuntimeException: boom, java.lang.RuntimeException: crash))
res3: cats.data.ValidatedNec[Throwable,List[Int]] = Valid(List(1, 2, 3))
其中
import cats.syntax.traverse._
import cats.instances.list._
import cats.syntax.either._
import scala.util.{Failure, Success, Try}
val la: List[Try[Int]] = List(Success(1), Success(2), Failure(new RuntimeException("boom")), Success(3), Failure(new RuntimeException("crash")))
val lb: List[Try[Int]] = List(Success(1), Success(2), Success(3))
没有错误累积,我们可以像这样进行排序
import cats.implicits._
la.sequence
输出
res0: scala.util.Try[List[Int]] = Failure(java.lang.RuntimeException: boom)
答案 1 :(得分:3)
这是第二个问题的解决方案。
case class CompoundError(errs: List[Throwable]) extends Throwable
def toTry[T](list: List[Try[T]]): Try[List[T]] =
list.partition(_.isSuccess) match {
case (res, Nil) =>
Success(res.map(_.get))
case (_, errs) =>
Failure(CompoundError(errs.collect { case Failure(e) => e }))
}
partition
操作将成功与失败分开,match
根据是否存在失败而返回适当的值。
先前的解决方案:
case class CompoundError(errs: List[Throwable]) extends Throwable
def toTry[T](list: List[Try[T]]): Try[List[T]] = {
val (res, errs) = list.foldLeft((List.empty[T], List.empty[Throwable])) {
case ((res, errs), item) =>
item match {
case Success(t) => (t :: res, errs)
case Failure(e) => (res, e :: errs)
}
}
errs match {
case Nil => Success(res.reverse)
case _ => Failure(CompoundError(errs.reverse))
}
}