如何简洁地检查Scala中的null或false?

时间:2011-06-20 20:15:25

标签: scala null

在Groovy语言中,检查nullfalse非常简单:

groovy代码:

def some = getSomething()
if(some) {
// do something with some as it is not null or emtpy 

}

在Groovy中,如果somenull或为空字符串或为零数字等,则评估为false。什么是Scala中nullfalse的类似简洁测试方法? 假设some只是Java类型的字符串?

,这部分问题的简单答案是什么?

另一个更好的方法是groovy:

def str = some?.toString()

这意味着如果some不是null,那么toString上的some方法将被调用,而不是在some为{{1}的情况下抛出NPE }}。 Scala有什么相似之处?

7 个答案:

答案 0 :(得分:51)

您可能缺少的是Scala中的getSomething函数可能不会返回null,空字符串或零数字。可能返回有意义值的函数或可能不会返回Option的函数 - 它将返回Some(meaningfulvalue)None

然后你可以检查这个并用

之类的东西处理有意义的值
 val some = getSomething()
 some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
 }

因此,Scala没有尝试对返回值中的“失败”值进行编码,而是对常见的“返回有意义的内容或指示失败”的情况进行了特定支持。

话虽如此,Scala可与Java互操作,而Java始终从函数中返回null。如果getSomething是一个返回null的Java函数,那么有一个工厂对象会使返回值中的Some或None。

所以

  val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

...这很简单,我声称,并且不会对你进行NPE。

其他答案正在做有趣和惯用的事情,但这可能比你现在所需的更多。

答案 1 :(得分:35)

好吧,Boolean不能是null,除非作为类型参数传递。处理null的方法是将其转换为Option,然后使用所有Option内容。例如:

Option(some) foreach { s => println(s) }
Option(some) getOrElse defaultValue

由于Scala是静态类型,因此不能“为null或为空字符串或为零数字等”。你可以传递Any这可能是任何一个东西,但是你必须匹配每种类型才能对它做任何有用的事情。如果你发现自己处于这种情况,你很可能没有做惯用的Scala。

答案 2 :(得分:19)

在Scala中,您描述的表达式意味着在名为?的对象上调用名为some的方法。通常,对象没有名为?的方法。您可以使用?方法创建自己的对象隐式转换,以检查null

implicit def conversion(x: AnyRef) = new {
  def ? = x ne null
}

上述内容实际上将您调用方法?的任何对象转换为方法conversion右侧的表达式( ?方法。例如,如果您这样做:

"".?

编译器将检测到String对象没有?方法,并将其重写为:

conversion("").?

在解释器中说明(请注意,在对象上调用方法时可以省略.):

scala> implicit def any2hm(x: AnyRef) = new {
     |   def ? = x ne null
     | }
any2hm: (x: AnyRef)java.lang.Object{def ?: Boolean}

scala> val x: String = "!!"
x: String = "!!"

scala> x ?
res0: Boolean = true

scala> val y: String = null
y: String = null

scala> y ?
res1: Boolean = false

所以你可以写:

if (some ?) {
  // ...
}

或者您可以使用?方法创建隐式转换为对象,如果参数不是null,则会调用对象上的指定方法 - 执行此操作:

scala> implicit def any2hm[T <: AnyRef](x: T) = new {
     |   def ?(f: T => Unit) = if (x ne null) f(x)
     | }
any2hm: [T <: AnyRef](x: T)java.lang.Object{def ?(f: (T) => Unit): Unit}

scala> x ? { println }
!!

scala> y ? { println }

这样你就可以写:

some ? { _.toString }

建立(递归地)关于soc的答案,您可以在上面的示例中对x进行模式匹配,以根据?的类型优化x所做的事情。 :d

答案 3 :(得分:7)

如果您使用extempore's null-safe coalescing operator,则可以将str示例写为

val str = ?:(some)(_.toString)()

它还允许您链接而不必担心null s(因此“合并”):

val c = ?:(some)(_.toString)(_.length)()

当然,这个答案只涉及你问题的第二部分。

答案 4 :(得分:6)

您可以自己编写一些包装器或使用Option类型。

我真的不会检查null。如果某个地方有null,你应该修复它而不是围绕它构建检查。

建立在axel22的答案之上:

implicit def any2hm(x: Any) = new {
  def ? = x match {
    case null => false
    case false => false
    case 0 => false
    case s: String if s.isEmpty => false
    case _ => true
  }
}

编辑:这似乎要么崩溃编译器,要么不起作用。我会调查。

答案 5 :(得分:6)

你要求的是Groovy的Safe Navigation Operator (?.),Ruby的andand gem或CoffeeScript的accessor variant of the existential operator (?.)。对于这种情况,我通常使用?的{​​{1}}方法,其定义如下

RichOption[T]

并按如下方式使用

class RichOption[T](option: Option[T]) {
  def ?[V](f: T => Option[V]): Option[V] = option match {
    case Some(v) => f(v)
    case _ => None
  }
}

implicit def option2RichOption[T](option: Option[T]): RichOption[T] =
  new RichOption[T](option)

答案 6 :(得分:0)

在这里使用模式匹配,这是一个很好的方法:

val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

但是,有点冗长。

我更喜欢以下列方式mapOption

Option(getSomething()) map (something -> doSomethingWith(something))

一条衬里,短而清晰。

原因是Option可以被视为some kind of collection - 集合的一些特殊雪花,它包含零元素或类型中的一个元素,并且您可以将List [A]映射到a列表[B],您可以将选项[A]映射到选项[B]。这意味着如果定义了Option [A]的实例,即它是Some [A],则结果为Some [B],否则为None。它真的很强大!