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

ace*_*ace 31 null scala

在Groovy语言中,检查null或更false喜欢它非常简单:

常规代码:

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

}
Run Code Online (Sandbox Code Playgroud)

在Groovy中,如果somenull或是空字符串或是零数字等将评估为false.在Scala中nullfalseScala 中测试的类似简洁方法是什么?这部分问题的简单答案是什么,假设some只是Java类型的String?

另外一个更好的方法是groovy:

def str = some?.toString()
Run Code Online (Sandbox Code Playgroud)

这意味着如果some不是null,则toString在方法some将被调用,而不是在壳体投掷NPE somenull.Scala有什么相似之处?

The*_*aul 51

您可能缺少的是,getSomethingScala 中的函数可能不会返回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")
 }
Run Code Online (Sandbox Code Playgroud)

因此,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")
  }
Run Code Online (Sandbox Code Playgroud)

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

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


Dan*_*ral 35

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

Option(some) foreach { s => println(s) }
Option(some) getOrElse defaultValue
Run Code Online (Sandbox Code Playgroud)

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


axe*_*l22 19

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

implicit def conversion(x: AnyRef) = new {
  def ? = x ne null
}
Run Code Online (Sandbox Code Playgroud)

上述的意志,在本质上,转换在其上调用方法的任何对象?到表达上的方法的右手侧conversion(其具有?法).例如,如果您这样做:

"".?
Run Code Online (Sandbox Code Playgroud)

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

conversion("").?
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

所以你可以写:

if (some ?) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

或者您可以使用一个?方法创建一个隐式转换为对象,如果参数不是,则调用对象上的指定方法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 }
Run Code Online (Sandbox Code Playgroud)

这样你就可以写:

some ? { _.toString }
Run Code Online (Sandbox Code Playgroud)

建立(递归地)关于soc的答案,你可以x在上面的例子中模式匹配,以?根据类型改进做什么x.:d


Aar*_*rup 7

如果您使用extempore的null-safe coalescing运算符,那么您可以将您的str示例编写为

val str = ?:(some)(_.toString)()
Run Code Online (Sandbox Code Playgroud)

它还允许你链接而不用担心nulls(因此"合并"):

val c = ?:(some)(_.toString)(_.length)()
Run Code Online (Sandbox Code Playgroud)

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


soc*_*soc 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
  }
}
Run Code Online (Sandbox Code Playgroud)

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


Vol*_*ıcı 6

你要求的是Groovy 的安全导航操作符(?.)和Ruby的gem,或者CoffeeScript 的存在操作符(?.)访问者变体.对于这种情况,我通常使用?my的方法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)
Run Code Online (Sandbox Code Playgroud)

并使用如下

scala> val xs = None
xs: None.type = None

scala> xs.?(_ => Option("gotcha"))
res1: Option[java.lang.String] = None

scala> val ys = Some(1)
ys: Some[Int] = Some(1)

scala> ys.?(x => Some(x * 2))
res2: Option[Int] = Some(2)
Run Code Online (Sandbox Code Playgroud)