如何将Seq [Try]转换为Try [Seq]

时间:2019-09-24 07:09:29

标签: scala

有了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并返回“复合”失败。

还有解决“复合”故障的解决方案吗?

2 个答案:

答案 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))
  }
}