使用多个选项和Eithers时避免嵌套Ifs

时间:2016-10-09 11:11:45

标签: scala

当我使用选项编码时,我发现折叠方法非常有用。而不是写我可以做的定义语句

opt.fold(<not_defined>){ defined => }

这很好。但如果我们正在使用多种选择该怎么办。或多个eithers。现在我不得不求助于编写像

这样的代码
if (x.isDefined && y.isRight) {
  val z = getSomething(x.get)
  if (z.isDefined) {
    ....

根据涉及的内容数量,此代码变得非常嵌套。

是否有一个功能性的技巧,使这个代码有点不嵌套和简洁....就像上面的折叠操作?

2 个答案:

答案 0 :(得分:1)

你尝试过理解吗?假设您不想处理个别错误或空选项:

import scala.util._

val opt1 = Some("opt1")
val either2: Either[Error, String] = Right("either2")
val try3: Try[String] = Success("try3")

for {
  v1 <- opt1
  v2 <- either2.right.toOption
  v3 <- try3.toOption
} yield {
  println(s"$v1 $v2 $v3")
}

请注意,Either没有正确的偏见,因此您需要在for comprehension上调用.right方法(我认为cat或scalaz具有正确的偏差Either)。此外,我们正在将EitherTry转换为选项,放弃错误

答案 1 :(得分:1)

.isDefined跟随.get调用的情况可以使用自定义提取器进行重构以进行模式匹配:

def getSomething(s: String): Option[String] = if (s.isEmpty) None else Some(s.toUpperCase)

object MyExtractor {
  def unapply(t: (Option[String], Either[Int, String])): Option[String] =
    t match {
      case (Some(x), Right(y)) => getSomething(x)
      case _ => None
    }
}

val x: Option[String] = Some("hello world")
val y: Either[Int, String] = Right("ok")

(x, y) match {
  case MyExtractor(z) => z // let's do something with z
  case _ => "world"
}
// HELLO WORLD

我们设法通过显式模式匹配替换所有.isDefined.get甚至.right调用,这要归功于我们的自定义提取器MyExtractor