2010-12-17 2 views
14

Класс Option Scala имеет метод orNull, подпись которого показана ниже.Пожалуйста, объясните использование метода Option или Null

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

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

+6

Увы, исходный код использует `Null <: 2010-12-17 10:49:23

ответ

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

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

<:<[Null, A1] можно записать в виде Null <:< A1 видя это, как это, он похож на «Null <: A1». <: < определен в Predef, а также метод, который предоставляет неявное значение с именем conforms.

Я думаю, что использование А1 не является строго обязательным здесь и потому, что 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 
+4

Видя подобные вещи, на самом деле трудно не любить Скала. – Madoc 2010-12-17 06:15:29

4

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

+0

ОК. Не могли бы вы привести пример использования? – David 2010-12-17 04:39:14

+0

Отмените это; Пример IttayD. Этот раздел «Программирование Scala» представляется релевантным: http://programming-scala.labs.oreilly.com/ch12.html#NothingAndNull. – David 2010-12-17 05:09:04

5

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

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

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

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

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

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

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

Чтобы понять, почему это полезно, IttayD provided a nice explanation:

Так что нам хотелось бы, это Защиту 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, и компилятор найдет неявный параметр.

Кстати, вот еще related answer.

0

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

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

Вместо того, чтобы более многословен:

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