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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6416925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:07:16  来源:igfitidea点击:

How to check for null or false in Scala concisely?

scalanull

提问by ace

In Groovy language, it is very simple to check for nullor falselike:

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

groovy code:

常规代码:

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

}

In Groovy if someis nullor is empty string or is zero number etc. will evaluate to false. What is similar concise method of testing for nullor falsein Scala? What is the simple answer to this part of the question assuming someis simply of Java type String?

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

Also another even better method in groovy is:

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

def str = some?.toString()

which means if someis not nullthen the toStringmethod on somewould be invoked instead of throwing NPE in case somewas null. What is similar in Scala?

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

回答by The Archetypal Paul

What you may be missing is that a function like getSomethingin Scala probably wouldn't return null, empty string or zero number. A function that might return a meaningful value or might not would have as its return an Option- it would return Some(meaningfulvalue)or None.

您可能缺少的是像getSomethingScala中的函数可能不会返回 null、空字符串或零数字。一个函数可能会返回一个有意义的值,也可能不会返回一个Option- 它会返回Some(meaningfulvalue)None

You can then check for this and handle the meaningful value with something like

然后,您可以检查这一点并使用类似的方法处理有意义的值

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

So instead of trying to encode the "failure" value in the return value, Scala has specific support for the common "return something meaningful or indicate failure" case.

因此,Scala 并没有尝试在返回值中编码“失败”值,而是对常见的“返回有意义的东西或指示失败”情况提供特定支持。

Having said that, Scala's interoperable with Java, and Java returns nulls from functions all the time. If getSomethingis a Java function that returns null, there's a factory object that will make Some or None out of the returned value.

话虽如此,Scala 可与 Java 互操作,而且 Java 始终从函数中返回空值。如果getSomething是一个返回 null 的 Java 函数,则有一个工厂对象可以从返回值中生成 Some 或 None 。

So

所以

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

... which is pretty simple, I claim, and won't go NPE on you.

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

The other answers are doing interesting and idiomatic things, but that may be more than you need right now.

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

回答by Daniel C. Sobral

Well, Booleancannot be null, unless passed as a type parameter. The way to handle nullis to convert it into an Option, and then use all the Optionstuff. For example:

好吧,Boolean不能是null,除非作为类型参数传递。处理的方法null是把它转换成一个Option,然后使用所有的Option东西。例如:

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

Since Scala is statically type, a thing can't be "a null or is empty string or is zero number etc". You might pass an Anywhich can be any of those things, but then you'd have to match on each type to be able to do anything useful with it anyway. If you find yourself in this situation, you most likely are not doing idiomatic Scala.

由于 Scala 是静态类型,因此事物不能是“空值或空字符串或零数字等”。您可能会传递 an Anywhich 可以是这些东西中的任何一个,但随后您必须匹配每种类型才能对其进行任何有用的操作。如果您发现自己处于这种情况,那么您很可能没有使用惯用的 Scala。

回答by axel22

In Scala, the expressions you described mean that a method called ?is invoked on an object called some. Regularly, objects don't have a method called ?. You can create your own implicit conversion to an object with a ?method which checks for nullness.

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

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

The above will, in essence, convert any object on which you call the method ?into the expression on the right hand side of the method conversion(which doeshave the ?method). For example, if you do this:

本质上,上面的代码会将调用方法的任何对象转换为方法?右侧的表达式conversion确实?方法)。例如,如果您这样做:

"".?

the compiler will detect that a Stringobject has no ?method, and rewrite it into:

编译器会检测到一个String对象没有?方法,并把它改写成:

conversion("").?

Illustrated in an interpreter (note that you can omit .when calling methods on objects):

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

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

So you could write:

所以你可以写:

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

Or you could create an implicit conversion into an object with a ?method which invokes the specified method on the object if the argument is not null- do this:

或者您可以创建一个隐式转换为一个对象,?如果参数不是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 }

so that you could then write:

这样你就可以写:

some ? { _.toString }

Building (recursively) on soc's answer, you can pattern match on xin the examples above to refine what ?does depending on the type of x. :D

根据 soc 的答案(递归地)构建,您可以x在上面的示例中进行模式匹配,以?根据x. :D

回答by Aaron Novstrup

If you use extempore's null-safe coalescing operator, then you could write your strexample as

如果您使用即席的空安全合并运算符,那么您可以将str示例编写为

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

It also allows you to chain without worrying about nulls (thus "coalescing"):

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

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

Of course, this answer only addresses the second part of your question.

当然,这个答案只解决了你问题的第二部分。

回答by Volkan Yaz?c?

What you ask for is something in the line of Safe Navigation Operator (?.)of Groovy, andand gemof Ruby, or accessor variant of the existential operator (?.)of CoffeeScript. For such cases, I generally use ?method of my RichOption[T], which is defined as follows

您要求的是Groovy的Safe Navigation Operator (?.)和 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)

and used as follows

并使用如下

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)

回答by soc

You could write some wrapper yourself or use an Option type.

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

I really wouldn't check for nullthough. If there is a nullsomewhere, you should fix it and not build checks around it.

null虽然我真的不会检查。如果有null某个地方,您应该修复它,而不是围绕它进行检查。

Building on top of axel22's answer:

建立在 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
  }
}

Edit: This seems to either crash the compiler or doesn't work. I'll investigate.

编辑:这似乎会使编译器崩溃或不起作用。我会调查的。

回答by Johnny

Using pattern matching as suggested in a couple of answers here is a nice approach:

使用这里几个答案中建议的模式匹配是一个不错的方法:

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

But, a bit verbose.

但是,有点啰嗦。

I prefer to mapan Optionin the following way:

我宁愿map一个Option以下列方式:

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

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

One liner, short, clear.

一个衬里,短,清晰。

The reason to that is Option can be viewed as some kind of collection– some special snowflake of a collection that contains either zero elements or exactly one element of a type and as as you can map a List[A] to a List[B], you can map an Option[A] to an Option[B]. This means that if your instance of Option[A] is defined, i.e. it is Some[A], the result is Some[B], otherwise it is None. It's really powerful!

这样做的原因是 Option 可以被视为某种集合——集合的一些特殊雪花,它包含零个元素或恰好一个类型的元素,就像你可以将 List[A] 映射到 List[B] ,您可以将 Option[A] 映射到 Option[B]。这意味着如果你的 Option[A] 实例被定义,即它是 Some[A],结果是 Some[B],否则它是 None。真的很强大!