我遇到的情况是我从外面收到一个树形数据结构,它可以有几种不同的形状。 我需要根据我得到的树种做一个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,但我找不到它。
答案 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 _ => ...
}