2011-06-20 16 views
31

が、それは次のようにnullまたはfalseをチェックするために非常に簡単です:Scalaでnullまたはfalseを簡潔にチェックする方法は? Groovyの言語で

グルーヴィーコード:Groovyで

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

} 

some等ゼロの数nullであるか、または空の文字列またはであるかどうかを評価します〜false。 Scalaでnullまたはfalseをテストする同様の簡潔な方法は何ですか? someが単純にJavaタイプのStringであると仮定すると、この部分の簡単な答えは何ですか?

さらにかっこいい内の別のより良い方法がある:somenullないならば、sometoString方法代わり場合someにNPEをスローで呼び出される手段

def str = some?.toString() 

nullました。 Scalaでは何が似ていますか?

+0

IMO、下記のダニエルの答えが最適です。 Scalaは、潜在的に空の値を扱うためのサポートを既にたくさん持っています。暗黙的に新しい '? '構文を作成するよりも、それを学び尽くす方が良いでしょう。 – Bill

+1

'None'の代わりに' null'sを使う理由の1つは、パフォーマンス/メモリの使用です。あなたは 'Option'ラッパーを保持する代わりに暗黙の変換から短命のオブジェクトを即座に割り当てることをお勧めします。確かに、多くの人がJVM上にハイパフォーマンスコードを書いているわけではありませんが、それでもユースケースがあると思います。 – axel22

答えて

49

スカラーのgetSomethingのような関数がnull、空の文字列またはゼロの数値を返さない可能性があります。意味のある値を返す可能性のある関数、または戻り値としてOptionを持つ可能性のある関数 - Some(meaningfulvalue)またはNoneを返します。

あなたは、このためにチェックして、だからではなく、戻り値に「失敗」値をエンコードしようとする、Scalaは一般的な「リターンのための具体的なサポートを持っている

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

ようなもので意味のある値を扱うことができます意味のあるものや失敗を示すもの "

これは、ScalaがJavaと相互運用可能であり、Javaが関数から常にnullを返すと言っています。 getSomethingがnullを返すJava関数である場合、戻り値からSomeまたはNoneを除外するファクトリオブジェクトがあります。私が主張する、非常に単純で、あなたにNPEを行くことはありませんので、

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

...。

他の回答は興味深いもので、慣用的なことをしていますが、それはあなたが今必要とする以上のものかもしれません。

+0

ありがとう!私はあなたのソリューションを使用して終了しましたが、申し訳ありませんが、すでに別の答えを解決策としてマークしていました。 – ace

+1

これは私の1ヶ月の旅でこれまでに遭遇した最悪のスカラー機能です。スカラーの「タイプレス」イデオロギーに対する邪教です。あなたはNPEを簡単に修正することができますし、あなたはあなたのためにすべてを行うlangに依存していません。オプションを指定しても、NPEにつながるコードを書くことができます。つまり、誰かがちょうどSome(val)をしたら大文字小文字にマッチするのではなく、NPEを取得します。多分これはもっと便利に見えるかもしれませんが、これまでのところ私は他のことを説明している記事に遭遇していません。 – nir

+0

あなたはあなたの気分を変えるでしょう。もちろん、あなたが試してみるとNPEを誘発することができますが、Scalaの良い習慣はOption .getを使わないことです - それを行うもっと良い方法がたくさんあります。 –

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上のパターンマッチを絞り込むことができますどのような? D卵はxの種類によって異なります。 :D

+0

これはいいです!この答えの要点を構成する 'eq'と' ne'演算子について説明できれば、それはもっと役に立ちます – asgs

+1

https://stackoverflow.com/questions/10066927/what-is-the-difference-between-スコープ内にヌルとヌルがある – axel22

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 
    } 
} 

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

+1

問題は、 'x'を' Any'と宣言すると、 '?'メソッドの2つの暗黙的な変換をスコープに導入することです。 – axel22

+0

Java String型のものがある場合はどうなりますか?スカラはグルーヴィーの簡潔さに欠けているようだ。 – ace

+0

申し訳ありませんが、私は両方の答えに従っているわけではありませんが、お試しいただきありがとうございます。私は単純な解決策を探していました。 – ace

33

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

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

、事は「ヌルまたは空の文字列であるか、またはゼロ数などある」ことができません。いずれにしてもAnyを渡すかもしれませんが、とにかく便利なことをするには、それぞれのタイプにマッチさせる必要があります。このような状況で自分自身が見つかった場合、あなたはおそらく慣用的なScalaをやっていないでしょう。

6

あなたがextempore's null-safe coalescing operatorを使用する場合、それはまた、あなたがおよそnull S(したがって、 "合体")を気にせずに連鎖することができます

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

として、あなたはあなたのstr例を書くことができます:の

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

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

0

次のように回答のカップルで提案されているような場合のために、私は一般的に、ここでいいです

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) 

を次のように定義された私のRichOption[T]?メソッドを使用し、使用しますアプローチ:

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として見ることができます。ゼロ要素または厳密に1つの要素のいずれかを含むコレクションの特別なスノーフレークであり、リスト[A]をリスト[B ]では、オプション[A]をオプション[B]に割り当てることができます。つまり、Option [A]のインスタンスが定義されている場合、つまりSome [A]の場合、結果はSome [B]、それ以外の場合はNoneです。それは本当に強力です!

関連する問題