如何在Scala中的长方法链中简洁地检查空值?
我的情况是,我从外部接收到一个树数据结构,它可以是几种不同的形状。 我需要做一个分类开关的情况下,根据什么样的树我得到。我正在编写的代码开始如下所示:如何在Scala中的长方法链中简洁地检查空值?,scala,Scala,我的情况是,我从外部接收到一个树数据结构,它可以是几种不同的形状。 我需要做一个分类开关的情况下,根据什么样的树我得到。我正在编写的代码开始如下所示: 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)
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...
root match {
case GotA(GotB(GotC(x))) => x
case GotA(GotD(GotE(x))) => x
}
“第一个”检查树是否有形状根->A->B->C…,“第二个”检查树是否有形状根->A->D->E。。。等
我觉得应该有一种更简单的方法在代码中表达这一想法,因为这些代码所做的只是通过包装和展开选项在每一步检查null,但我找不到它。您可以:
val first = Try(root.getA.getB.getC).toOption
但这可能很慢,不推荐使用。让您的getN
方法返回选项
,并按照您最初的意图使用它们的更好方法,但为了便于理解:
val first = for {
a <- root.getA
b <- a.getB
c <- b.getC
...
val first=for{
a你可以做:
val first = Try(root.getA.getB.getC).toOption
但这可能很慢,不推荐使用。让您的getN
方法返回Option
,并按照您最初的意图使用它们的更好方法,但为了便于理解:
val first = for {
a <- root.getA
b <- a.getB
c <- b.getC
...
val first=for{
a如果getA
等是带有getValue(“a”)
等参数的占位符,则可以编写一个简单的函数,该函数取根
和(“a”、“B”、“C”)
,并在树中轻松遍历检查空值。我假设您提出了这个问题,因为它不是这么简单。但是,您可以使用反射对方法调用进行参数化
如果树相对较小或Scala代码正在执行大部分工作,则另一种可能性是递归地复制树并将其转换为更易于处理的类似Scala的结构。如果您感觉特别扭曲,可以将其转换为XML文档,然后使用XML pr使用模式匹配模仿
或者,如果不同的getX
函数相对较少,则可以编写自定义提取器:
object GotA {
def unapply(x: Thing) = Option(x) map {_.getA}
}
然后,您的代码将变成简单的模式匹配,如下所示:
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...
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
val first=for{
a如果getA
等是带有getValue(“a”)
等参数的占位符,则可以编写一个简单的函数,该函数取根
和(“a”、“B”、“C”)
,并在树中轻松遍历检查空值。我假设您提出了这个问题,因为它不是这么简单。但是,您可以使用反射对方法调用进行参数化
如果树相对较小或Scala代码正在执行大部分工作,则另一种可能性是递归地复制树并将其转换为更易于处理的类似Scala的结构。如果您感觉特别扭曲,可以将其转换为XML文档,然后使用XML pr使用模式匹配模仿
或者,如果不同的getX
函数相对较少,则可以编写自定义提取器:
object GotA {
def unapply(x: Thing) = Option(x) map {_.getA}
}
然后,您的代码将变成简单的模式匹配,如下所示:
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...
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
val first=for{
a你可以这样做
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 _ => ...
}
你可以这样做
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 _ => ...
}
像这样使用Try
不仅可能很慢,而且可能是不正确的:它捕获的不仅仅是NullPointerException
,它还捕获getter本身抛出的NPE。@MadameElyse是这样的。当我看到Try
像这样时,我认为getA
抛出了一些东西,而不是这个Try
的原因是getA
可以返回null。但是我已经向作者提出了这个建议,因为他想要比他拥有的更短的东西,我认为没有其他更多的更短的选项。这个选项非常不推荐使用,最好的、可读的和简单的方法是为了理解scala中的yTry
不是由Predef
导入的-因为它几乎不应该被使用,因为它不仅可能很慢,而且可能是不正确的:它捕获的不仅仅是NullPointerException
,它还捕获由getter本身抛出的NPE。@MadameElyse是这样的。而且恩,我看到Try
像这样,我想getA
抛出了一些东西,但我从来没有想到这个Try
的原因是getA
可以返回null。但是我向作者提出了这个建议,因为他想要比他拥有的更短的东西,而且我认为没有很多其他更短的选择。这个选择非常有用推荐使用,最好的、可读的和简单的方法是为了理解,Predef
没有导入scala中的Try
,这是有原因的,因为它几乎永远都不应该被使用。我唯一真正做的改变是,我替换了“compilementunit”、“ClassDeclaration”、“InterfaceDeclaration”之类的东西我所做的唯一真正的改变是,我用A、B和C替换了“compileationunit”、“ClassDeclaration”、“InterfaceDeclaration”等内容(节点类源自ANTLR A解析器生成器)