请解释使用Option的orNull方法

时间:2010-12-17 04:06:46

标签: api scala scala-java-interop

Scala的Option类有一个orNull方法,其签名如下所示。

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

我被隐含的东西弄糊涂了。有人请说明如何使用它,理想情况下是一个例子吗?

5 个答案:

答案 0 :(得分:30)

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] = ....。但是A已经设置好了,我们不想在特征的定义中限制它。因此,orNull期望证明A是可以为空的类型。该证据采用隐式变量的形式(因此名称为'ev')

<:<[Null, A1]可以写成Null <:< A1,就像这样,它类似于'Null&lt ;: A1'。 &LT;:其中在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

答案 1 :(得分:5)

orNull目的首先是确保Option与Java的兼容性。虽然不鼓励在Scala中使用null,但某些接口可能会获得可以为空的引用。

orNull有一个简单的实现:

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

根据这一点,null不仅会返回盒装空值(Some(null)),还会返回None(例如,如果您调用None.get,则异常将被抛出)。

如果装箱值可以为空,则隐式参数检查。

可以在comments to orNull

中找到好用法示例
val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)

答案 2 :(得分:4)

请记住,在Scala中,原始类型和引用类型是统一的 - 但只有引用类型可以为空。隐式只允许编译器确认A1是引用类型。

答案 3 :(得分:2)

要理解它有用的原因,IttayD provided a nice explanation

  

所以我们喜欢的是def   orNull[A >: Null] = .....但是A是   已经设定,我们不想   限制它的定义   特征。因此,orNull期望一个   A是可以为空的类型的证据。   这个证据的形式是   隐式变量(因此名称   的EV')

总之,当您希望在具有更多特定约束(例如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]的{​​{1}}。这适用于<:<[Null, String],因为A = StringNull的子类型,而类String的{​​{1}}类型参数被定义为逆变)。

如上所述,考虑类型约束的最直观方式是将其读取为类型绑定(即将其读取为Null&lt;:Int)。 From不符合<:<且&lt;:&lt; [Null,Int]没有隐含值。另一方面,Null符合Int,编译器将找到隐含参数。

顺便说一下,这是另一个related answer

答案 4 :(得分:0)

Re:'如何'使用 - 我们发现这个有用的地方是在处理{ap}映射时null是常见的,例如在jdbc上准备了可以为nullable的sql列的语句。可以映射Option内部模型字段:

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

而不是更详细:

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