3

我有一个输入值列表

List[A]

和一个函数

f(List[A]): Either[Failure, Success]

我将该函数应用于列表的每个元素,生成一个List[Either[Failure, Success]].

我想检查列表,如果任何值失败,则返回第一个失败,否则返回成功列表。

我使用了以下模式:

val allValues = list.map(f(_))
if (allValues.exists(_.isLeft)) {
  allValues.find(_.isLeft).get
} else {
  allValues.collect {
    case Right(result) => result
  }
}

val allValues = list.map(f(_))
val failures = allValues.collect { case Left(error) => error }
if (failures.nonEmpty) {
  failures(0)
} else {
  allValues.collect {
    case Right(result) => result
  }
}

有没有更简洁的方式来表达这种模式?

有时,我必须通过另一个函数进一步处理成功,再次使用相同的模式。例如

  • 将 JSON 数组转换为 Scala 模型,如果任何 JSON 对象格式错误,则会失败。
  • 将模型写入数据库并在任何数据库更新失败时失败。
4

2 回答 2

12

听起来好像您希望将 aList[Either[Failure, Success]]转换为Either[Failure, List[Success]]? 您可以使用toLeft.

result collectFirst { case Left(f) => f } toLeft {
    result collect { case Right(r) => r}
}

collectFirst接受 a PartialFunction[A, B],它将应用于List具有已定义输出的第一个元素,并将返回Option[B]. 在这种情况下,我尝试从 中提取第一个Left(f)List所以我会得到Option[Failure].

然后,我调用toLeft. 如果包含一个值,Option[Failure]这将Failure再次将单转换为,如果为空,则参数将产生该值。LeftOptionRightOption

如果Option确实是空的,那么我提取成功 using collect,类似于 using collectFirst,不同之处在于它保留了List定义PartialFunctionthe 的所有元素。

于 2015-01-22T14:31:16.103 回答
1

这应该工作

l.collectFirst { case Left(error) => error }.getOrElse {
     l.map(_.right)
 } 

l名单在哪里Either[Left, Right]

例如:

万一出现错误

val l = List(Right(1), Right(2), Left(3), Left(4), Right(5))
l.collectFirst { case Left(error) => error }.getOrElse {
     l.map(_.right)
 } //res0: Any = 3

它返回any,因为它可以返回Failure或列表 Success

于 2015-01-22T14:19:38.553 回答