Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Scala中的长方法链中简洁地检查空值?_Scala - Fatal编程技术网

如何在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中的y
Try
不是由
Predef
导入的-因为它几乎不应该被使用,因为它不仅可能很慢,而且可能是不正确的:它捕获的不仅仅是
NullPointerException
,它还捕获由getter本身抛出的NPE。@MadameElyse是这样的。而且恩,我看到
Try
像这样,我想
getA
抛出了一些东西,但我从来没有想到这个
Try
的原因是
getA
可以返回null。但是我向作者提出了这个建议,因为他想要比他拥有的更短的东西,而且我认为没有很多其他更短的选择。这个选择非常有用推荐使用,最好的、可读的和简单的方法是为了理解,
Predef
没有导入scala中的
Try
,这是有原因的,因为它几乎永远都不应该被使用。我唯一真正做的改变是,我替换了“compilementunit”、“ClassDeclaration”、“InterfaceDeclaration”之类的东西我所做的唯一真正的改变是,我用A、B和C替换了“compileationunit”、“ClassDeclaration”、“InterfaceDeclaration”等内容(节点类源自ANTLR A解析器生成器)