web-dev-qa-db-ja.com

Scala簡潔にnullまたはfalseをチェックする方法?

Groovy言語では、次のようにnullまたはfalseを確認するのは非常に簡単です。

グルーヴィーなコード:

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

}

Groovyでは、somenullであるか、空の文字列であるか、数値がゼロなどの場合、falseと評価されます。 Scalaでnullまたはfalseをテストする同様の簡潔な方法は何ですか? someが単純にJava type String?

また、Groovyのもう1つの優れた方法は次のとおりです。

def str = some?.toString()

つまり、somenullではない場合、toStringsomeであった場合にNPEをスローする代わりに、somenullメソッドが呼び出されます。 [$ var] _。 Scalaで似ているのは何ですか?

31
ace

不足している可能性があるのは、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がJava null、返された値からSomeまたはNoneを生成するファクトリオブジェクトがあります。

そう

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

...これは非常に単純で、私は主張し、あなたにNPEはしません。

他の答えは、おもしろくて慣用的なことをしているが、それはあなたが今必要としている以上のものかもしれない。

51

Booleanは、型パラメーターとして渡されない限り、nullにはできません。 nullを処理する方法は、Optionに変換してから、すべてのOptionを使用することです。例えば:

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

Scalaは静的に型であるため、Thingは "nullまたは空文字列またはゼロ番号などにはできません。Anyこれはそれらのいずれでも構いませんが、とにかくそれを使って何か便利なことができるようにするには、それぞれのタイプで一致する必要があります。

35

Scalaでは、説明した式は、?というメソッドがsomeというオブジェクトで呼び出されることを意味します。通常、オブジェクトには?というメソッドがありません。 nullnessをチェックする?メソッドを使用して、オブジェクトへの暗黙的な変換を作成できます。

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

上記は、本質的に、メソッド?を呼び出すオブジェクトをメソッドconversionの右側の式に変換します(これはdoesを持ちます) ?メソッド)。たとえば、これを行う場合:

"".?

コンパイラは、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

19
axel22

extemporeのヌルセーフ合体演算子 を使用する場合、次のようにstrの例を書くことができます。

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

また、nullsを気にせずに連鎖することができます(つまり、「結合」)。

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

もちろん、この答えはあなたの質問の2番目の部分のみを扱っています。

7
Aaron Novstrup

求めるのは、 Safe Navigation Operator(?。) Groovy、 and and gem of Ruby、または 実在演算子のアクセサバリアント(?。) CoffeeScriptの。このような場合、通常、?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)

そして次のように使用されます

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)
6
Volkan Yazıcı

ラッパーを自分で作成するか、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
  }
}

編集:これは、コンパイラをクラッシュさせるか、動作しないようです。調査します。

6
soc

ここでいくつかの回答で提案されているパターンマッチングを使用するのは、素晴らしいアプローチです。

_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))

ライナー1本、短く、透明。

その理由は、Optionが コレクションの種類 –リストのゼロ要素またはタイプの要素を1つだけ含むコレクションの特別なスノーフレークとして表示できるためです。List[A ]をリスト[B]に、オプション[A]をオプション[B]にマッピングできます。つまり、Option [A]のインスタンスが定義されている場合、つまりSome [A]の場合、結果はSome [B]になり、そうでない場合はNoneになります。本当にパワフルです!

0
Johnny