Пожалуйста, объясните использование метода Option илиNull

Scala Класс option имеет метод orNull, подпись которого показана ниже.

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

Я смущен неявной вещью. Кто-нибудь, пожалуйста, объясните, как это можно использовать, в идеале с примером?

Ответ 1

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 idiom (что, конечно, плохо). Теперь только значения AnyRef (экземпляры классов) могут принимать нулевое значение.

Итак, нам бы понравилось def orNull[A >: Null] = ..... Но А уже установлен, и мы не хотим ограничивать его в определении признака. Поэтому orNull ожидает доказательства того, что A является типом с нулевым значением. Это доказательство находится в форме неявной переменной (отсюда и имя "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

Ответ 2

orNull Целью является, в первую очередь, обеспечение совместимости Option с Java. Хотя использование null не рекомендуется в Scala, некоторые интерфейсы могут ожидать получения ссылок с нулевым значением.

orNull имеет прямую реализацию:

def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

В соответствии с этим, null будет возвращен не только для вложенных нулей (Some(null)), но и для None (например, если вы вызываете None.get, будет выбрано исключение).

Неявные проверки параметров, если значение в ящике равно NULL.

Хороший пример использования можно найти прямо в комментариях к orNull:

val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)

Ответ 3

Помните, что в Scala примитивные типы и ссылочные типы унифицированы, но только ссылочные типы имеют значение NULL. Неявный просто позволяет компилятору подтвердить, что A1 является ссылочным типом.

Ответ 4

Чтобы понять, почему это полезно, IttayD предоставил приятное объяснение:

Так что нам бы понравилось orNull[A >: Null] = ..... Но А уже установлены, и мы не хотим ограничить его в определении черта. Следовательно, orNull ожидает что A - тип с нулевым значением. Это свидетельство имеет форму неявная переменная (отсюда и название 'Эв')

Таким образом, ограничения типа полезны, когда вы хотите иметь методы (например, orNull) для общего класса (например, Option) с более конкретными ограничениями (например, Null <: A <: Any), чем для самого класса (например, A <: Any).

Это еще одна "функция", которая не встроена в язык, но предоставляется бесплатно благодаря неявным параметрам и аннотациям параметров типа. Чтобы понять это, посмотрите на определение <:<:

// 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, для которого <:<[A, A] соответствует <:<[Null, Int]. Нет A, для которого это выполняется, и в результате компилятор будет жаловаться на недостающее неявное значение.

Однако для

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

нам повезло. Теперь компилятор пытается найти A, для которого <:<[A, A] соответствует <:<[Null, String]. Это работает для A = String, потому что Null является подтипом String, а параметр типа From класса <:< определяется как контравариантный).

Как уже упоминалось, наиболее интуитивным способом думать о ограничениях типа является чтение его как привязка типа (т.е. чтение его как Null <: Int). Null не соответствует Int, и нет никакого неявного значения для <: < [Null, Int]. С другой стороны, Null соответствует String, а компилятор найдет неявный параметр.

Кстати, вот еще один связанный ответ.

Ответ 5

Re: "как" это используется - одно место, которое мы находим полезным, - это когда мы имеем дело с java-api-сопоставлениями, где null является обычным явлением, например. на jdbc подготовленные операторы для нулевых столбцов sql. Внутренние поля модели Option al могут быть отображены:

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

Вместо более подробного:

stmt.setDate("field", myModel.myDateField.getOrElse(null))