我对字符串列表进行了一些数据转换,并得到了一个列表,其中 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)
使用.get被认为是“代码味道”:在这种情况下它会起作用,但会让代码的读者暂停并花费一些额外的“周期”来“证明”它是好的。最好避免使用.getonEither和Optionor .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)