如何将“Either”列表转换为“Right”值列表?

Chr*_*yer 5 scala either

我对字符串列表进行了一些数据转换,并得到了一个列表,其中 Left 表示错误,Right 表示转换成功的项目。

val results: Seq[Either[String, T]] = ... 
Run Code Online (Sandbox Code Playgroud)

我将结果划分为:

val (errors, items) = results.partition(_.isLeft)
Run Code Online (Sandbox Code Playgroud)

做了一些错误处理后,我想返回一个Seq[T]有效的项目。这意味着,返回所有 Right 元素的值。由于分区,我已经知道 items 的所有元素Right。我想出了五种可能的方法。但是在可读性和性能方面什么是最好的?在 Scala 中是否有一种惯用的方法来做到这一点?

// which variant is most scala like and still understandable?
items.map(_.right.get)
items.map(_.right.getOrElse(null))
items.map(_.asInstanceOf[Right[String, T]].value)
items.flatMap(_.toOption)
items.collect{case Right(item) => item}
Run Code Online (Sandbox Code Playgroud)

Dim*_*ima 5

使用.get被认为是“代码味道”:在这种情况下它会起作用,但会让代码的读者暂停并花费一些额外的“周期”来“证明”它是好的。最好避免使用.getonEitherOptionor .applyon aMap或 a 之类的东西IndexedSeq

.getOrElse没问题……但这null不是你在 scala 代码中经常看到的东西。再次,让读者停下来思考“为什么会在这里?如果它最终返回 null 会发生什么?” 等等,最好也避免。

.asInstanceOf是……很糟糕。它破坏了类型安全,而且……不是 scala。

那留下.flatMap(_.toOption).collect。两者都很好。我个人更喜欢后者,因为它更明确一点(并且不会让读者停下来记住哪种方式Either有偏见)。

您还可以使用foldRight“一次”完成分区和提取:

 val (errors, items) = results.foldRight[(List[String], List[T])](Nil,Nil) { 
    case (Left(error), (e, i)) => (error :: e, i)
    case ((Right(result), (e, i)) => (e, result :: i)
 }
Run Code Online (Sandbox Code Playgroud)