ScalaのOptionクラスにはorNull
メソッドがあり、そのシグネチャを以下に示します。
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
私は暗黙のことで当惑しています。誰かがそれがどのように使われることができるか、理想的には例を挙げて説明してもらえますか?
ScalaのOptionクラスにはorNull
メソッドがあり、そのシグネチャを以下に示します。
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
私は暗黙のことで当惑しています。誰かがそれがどのように使われることができるか、理想的には例を挙げて説明してもらえますか?
scala> Some(1).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
Some(1).orNull
^
scala> (None : Option[Int]).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
(None : Option[Int]).orNull
scala> Some("hi").orNull
res21: java.lang.String = hi
scala> Some(null : String).orNull
res22: String = null
scala> (None : Option[String]).orNull
res23: String = null
暗黙のことを説明すると、orNullは、Some|NoneイディオムからJavaのvalue|nullイディオム(もちろん悪い)に戻る方法です。これで、AnyRef値(クラスのインスタンス)のみがnull値を受け入れることができます。
だから私たちが好きだったのはdef orNull[A >: Null] = ....
です。ただし、Aはすでに設定されているため、特性の定義でAを制限したくありません。したがって、orNullは、Aがnull許容型であるという証拠を期待します。この証拠は、暗黙の変数の形式です(したがって、「ev」という名前)
<:<[Null, A1]
このように見えるように書くことができますNull <:< A1
、それは'Null <:A1'に似ています。<:<は、Predefと、という名前の暗黙の値を提供するメソッドで定義されますconforms
。
ここではA1の使用は厳密には必須ではなく、orNullがgetOrElseを使用しているためだと思います(デフォルトではAのスーパータイプにすることができます)
scala> class Wrapper[A](option: Option[A]) {
| def orNull(implicit ev: Null <:< A): A = if(option.isEmpty) null else option.get
| }
defined class Wrapper
scala> new Wrapper(Some("hi")).orNull
res18: java.lang.String = hi
orNull
目的は、まずOption
Javaとの互換性を確保することです。Scalaではの使用null
は推奨されていませんが、一部のインターフェースはnull許容の参照を取得することを期待する場合があります。
orNull
簡単な実装があります:
def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null
これによると、null
ボックス化されたnull(Some(null)
)だけでなく、None
(たとえば、を呼び出すNone.get
と例外がスローされます)に対しても返されます。
ボックス化された値がnull許容であるかどうか、暗黙のパラメーターチェック。
良い使用例は、次のコメントにorNull
あります。
val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)
Scalaでは、プリミティブ型と参照型が統一されていることを忘れないでください。ただし、null許容できるのは参照型だけです。暗黙的に、コンパイラはA1が参照型であることを確認できます。
それがなぜ有用であるかを理解するために、IttayDは素晴らしい説明を提供しました:
したがって、私たちが望んでいたのはdefですが
orNull[A >: Null] = .....
、Aはすでに設定されており、特性の定義で制限したくありません。したがって、orNullは、Aがnull許容型であるという証拠を期待します。この証拠は、暗黙の変数の形式です(したがって、「ev」という名前)
要約すると、型制約は、クラス自体(eg)よりも具体的な制約(eg)を持つorNull
ジェネリッククラス(eg)にメソッド(eg)を持たせたい場合に役立ちます。Option
Null <: A <: Any
A <: Any
これは、言語に組み込まれていないもう1つの「機能」ですが、暗黙的なパラメーターとタイプパラメーターの分散アノテーションのおかげで無料で提供されます。これを理解するには、次の定義を見てください<:<
。
// from Predef
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
にとって
scala> Some(1).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
Some(1).orNull
コンパイラは型の暗黙の値を<:<[Null, Int]
探し、メソッドを見つけますdef conforms[A]: A <:< A
。したがって、に準拠するA
forが必要です。これが当てはまるものはなく、その結果、コンパイラは暗黙の値が欠落していることについて文句を言います。<:<[A, A]
<:<[Null, Int]
A
ただし、
scala> Some("hi").orNull
res21: java.lang.String = hi
私たちはラッキーです。ここで、コンパイラはに準拠するA
forを見つけようとします。はのサブタイプであり、クラスのタイプパラメータは反変として定義されているため、これはに対して機能します。<:<[A, A]
<:<[Null, String]
A = String
Null
String
From
<:<
前述のように、型制約について考える最も直感的な方法は、型の制約のように読み取ることです(つまり、Null <:Intとして読み取ることです)。Null
に準拠しておらずInt
、<:<[Null、Int]の暗黙の値はありません。一方、Null
に準拠してString
おり、コンパイラは暗黙のパラメータを見つけます。
ちなみに、ここに別の関連する答えがあります。
Re:「どのように」これが使用されます-これが有用であると私たちが見つけた1つの場所は、null
一般的なjava apiマッピングを処理するときです。たとえば、null許容SQL列へのjdbcプリペアドステートメントなどです。すべてのOption
内部モデルフィールドをマッピングできます。
stmt.setDate("field", myModel.myDateField.orNull)
より冗長な代わりに:
stmt.setDate("field", myModel.myDateField.getOrElse(null))