18

ScalaのOptionクラスにはorNullメソッドがあり、そのシグネチャを以下に示します。

orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1

私は暗黙のことで当惑しています。誰かがそれがどのように使われることができるか、理想的には例を挙げて説明してもらえますか?

4

5 に答える 5

31
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
于 2010-12-17T04:42:02.457 に答える
5

orNull目的は、まずOptionJavaとの互換性を確保することです。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)
于 2010-12-17T07:59:05.697 に答える
4

Scalaでは、プリミティブ型と参照型が統一されていることを忘れないでください。ただし、null許容できるのは参照型だけです。暗黙的に、コンパイラはA1が参照型であることを確認できます。

于 2010-12-17T04:14:21.947 に答える
2

それがなぜ有用であるかを理解するために、IttayDは素晴らしい説明を提供しました

したがって、私たちが望んでいたのはdefですが orNull[A >: Null] = .....、Aはすでに設定されており、特性の定義で制限したくありません。したがって、orNullは、Aがnull許容型であるという証拠を期待します。この証拠は、暗黙の変数の形式です(したがって、「ev」という名前)

要約すると、型制約は、クラス自体(eg)よりも具体的な制約(eg)を持つorNullジェネリッククラス(eg)にメソッド(eg)を持たせたい場合に役立ちます。OptionNull <: A <: AnyA <: 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。したがって、に準拠するAforが必要です。これが当てはまるものはなく、その結果、コンパイラは暗黙の値が欠落していることについて文句を言います。<:<[A, A]<:<[Null, Int]A

ただし、

scala> Some("hi").orNull
res21: java.lang.String = hi

私たちはラッキーです。ここで、コンパイラはに準拠するAforを見つけようとします。はのサブタイプであり、クラスのタイプパラメータは反変として定義されているため、これはに対して機能します。<:<[A, A]<:<[Null, String]A = StringNullStringFrom<:<

前述のように、型制約について考える最も直感的な方法は、型の制約のように読み取ることです(つまり、Null <:Intとして読み取ることです)。Nullに準拠しておらずInt、<:<[Null、Int]の暗黙の値はありません。一方、Nullに準拠してStringおり、コンパイラは暗黙のパラメータを見つけます。

ちなみに、ここに別の関連する答えがあります。

于 2010-12-20T15:02:31.530 に答える
0

Re:「どのように」これが使用されます-これが有用であると私たちが見つけた1つの場所は、null一般的なjava apiマッピングを処理するときです。たとえば、null許容SQL列へのjdbcプリペアドステートメントなどです。すべてのOption内部モデルフィールドをマッピングできます。

stmt.setDate("field", myModel.myDateField.orNull)

より冗長な代わりに:

stmt.setDate("field", myModel.myDateField.getOrElse(null))
于 2014-05-22T13:37:36.383 に答える