将一系列 ZIO 的所有成功和失败集中在一起?

Collect all of the successes and failures of a sequence of ZIOs together?

我有一堆IO,所有这些都可能成功或失败:

val result: Seq[IO[MyFailure, MySuccess]] = ...

我需要总结结果,以便我可以检查所有失败和所有成功一起:

case class MySummary(failures: Seq[MyFailure], successes: Seq[MySuccess])
def makeSummary(results: Seq[IO[MyFailure, MySuccess]]): UIO[MySummary] = ???

起初这似乎与 foreach 非常相似,但仔细检查后我发现这对这里没有帮助。对于 Future 我通常使用 sequence,对于 Seq[Either[A,B]] 我可以使用 partitionMap。 ZIO 中的等效方法是什么?

我对 ZIO 不熟悉,可能有一种内置的方法可以实现相同的目的。

我会选择以下内容:

def makeSummary(results: Seq[IO[MyFailure, MySuccess]]): UIO[MySummary] = {
  results.foldLeft(ZIO.succeed(MySummary(Seq(), Seq()))) { (acc, io) =>
    acc.flatMap { summary => 
      io.fold(
        err => summary.copy(failures = summary.failures :+ err),
        suc => summary.copy(successes = summary.succcesses :+ suc)
      )
    }
  }
}

您无法使用 Future.sequence 检查所有失败,如果有的话,您只会返回第一个失败。

Future.sequence 的 ZIO 等价物是 ZIO.collectAll,这几乎等同于 ZIO.foreach(result)(identity)

如果你真的需要累积所有错误,那么你应该使用 ZIO.validate 并且对于分区还有 ZIO.partition.

一些比较代码:

  val result: Seq[IO[MyFailure, MySuccess]] = ???

  val withCollectAll: IO[MyFailure, Seq[MySuccess]] = ZIO.collectAll(result)
  val withForeach: IO[MyFailure, Seq[MySuccess]] = ZIO.foreach(result)(identity)
  val withValidate: IO[::[MyFailure], Seq[MySuccess]] = ZIO.validate(result)(identity) //`::` just means that the list cannot be empty
  val withPartition: UIO[(Iterable[MyFailure], Iterable[MySuccess])] = ZIO.partition(result)(identity)

makeSummary 的代码 ZIO.partition:

  def makeSummary(results: Seq[IO[MyFailure, MySuccess]]): UIO[MySummary] =
    ZIO.partition(results)(identity).map { case (f, s) => MySummary(f.toSeq, s.toSeq) }