如何在Scala中的长方法链中简明地检查空值?

时间:2016-01-27 11:28:19

标签: scala

我遇到的情况是我从外面收到一个树形数据结构,它可以有几种不同的形状。 我需要根据我得到的树种做一个sorta switch case。我写的代码开始看起来像这样:

val first = Option(root.getA)
    .flatMap(o => Option(o.getB))
    .flatMap(o => Option(o.getC))
...
val second = Option(root.getA)
    .flatMap(o => Option(o.getD))
    .flatMap(o => Option(o.getE))
...
first.getOrElse(second.getOrElse...

'first'检查树是否具有形状root-> A-> B-> C ...,'second'检查树是否具有形状root-> A-> D- > E ...等 我觉得在代码中应该有一种更简单的方式来表达这个想法,因为所有这些代码都在做的是通过包装和解包选项来检查每一步的null,但我找不到它。

3 个答案:

答案 0 :(得分:1)

你可以这样做:

val first = Try(root.getA.getB.getC).toOption

但这可能很慢,不推荐。更好的方法是让getN方法返回Option,并按照您的意图使用它们,但需要理解:

val first = for {
       a <- root.getA
       b <- a.getB
       c <- b.getC
       ...

答案 1 :(得分:1)

如果getA等是带有getValue("A")等参数的占位符,则可以编写一个简单的函数,该函数使用root("A", "B", "C")并轻松遍历树检查空值一路上。我假设您已经问过这个问题,因为事情并非如此简单。但是,您可以使用反射参数化方法调用

如果树相对较小或者您的Scala代码执行大部分工作,则另一种可能性是以递归方式将树复制并转换为更易于处理的类似Scala的结构。如果您感觉特别扭曲,可以将其转换为XML文档,然后使用XML原语进行模式匹配。

或者,如果相对较少的getX函数相对较少,您可以编写自定义提取器:

object GotA {
  def unapply(x: Thing) = Option(x) map {_.getA}
}

然后你的代码变成了简单的模式匹配:

root match {
   case GotA(GotB(GotC(x))) => x
   case GotA(GotD(GotE(x))) => x
}

如果节点查找规则非常不规则,以至于它们不适合这些方法中的任何一种,那么您至少可以使用与您所提供的等效代码相符的理解,您可以找到更美观的:

val first = for {
  a <- Option(root.getA)
  b <- Option(a.getB)
  c <- Option(b.getC)
} yield c

可悲的是,因为您已经严重匿名化了这个问题,并且没有说明需要多少次这些查询或者它们有多复杂,我无法推荐具体的解决方案。

答案 2 :(得分:0)

你可以这样做

case class Node(val a: Node, val b: Node, val c: Node, val data: Int)

node match {
    case Node(a: Node, b: Node, c: Node, _) => ...
    case Node(null, b: Node, c: Node, _) => ...
    case Node(a: Node, null, c: Node, _) => ...
    case Node(a: Node, b: Node, null, _) => ...
    case _ => ...
}