在Groovy语言中,检查null
或false
非常简单:
groovy代码:
def some = getSomething()
if(some) {
// do something with some as it is not null or emtpy
}
在Groovy中,如果some
为null
或为空字符串或为零数字等,则评估为false
。什么是Scala中null
或false
的类似简洁测试方法?
假设some
只是Java类型的字符串?
另一个更好的方法是groovy:
def str = some?.toString()
这意味着如果some
不是null
,那么toString
上的some
方法将被调用,而不是在some
为{{1}的情况下抛出NPE }}。 Scala有什么相似之处?
答案 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")
}
但是,有点冗长。
我更喜欢以下列方式map
和Option
:
Option(getSomething()) map (something -> doSomethingWith(something))
一条衬里,短而清晰。
原因是Option可以被视为some kind of collection - 集合的一些特殊雪花,它包含零元素或类型中的一个元素,并且您可以将List [A]映射到a列表[B],您可以将选项[A]映射到选项[B]。这意味着如果定义了Option [A]的实例,即它是Some [A],则结果为Some [B],否则为None。它真的很强大!