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 值(类的实例)可以接受空值。

所以我们会喜欢的是def orNull[A >: Null] = ..... 但是 A 已经设置好了,我们不想在 trait 的定义中限制它。因此, 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
于 2010-12-17T04:42:02.457 回答
5

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

orNull有一个简单的实现:

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

据此,null不仅会为装箱的空值 ( Some(null)) 返回,而且还会为None(例如,如果您调用None.get,将引发异常)返回。

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

好的用法示例可以在以下评论中orNull找到:

val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)
于 2010-12-17T07:59:05.697 回答
4

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

于 2010-12-17T04:14:21.947 回答
2

为了理解它为什么有用,IttayD 提供了一个很好的解释

所以我们想要的是 def orNull[A >: Null] = .....但是 A 已经设置好了,我们不想在 trait 的定义中限制它。因此, orNull 期望 A 是可空类型的证据。该证据采用隐式变量的形式(因此名称为“ev”)

总而言之,当您希望orNull泛型类(例如)上的方法(例如)具有比类本身(例如)Option更具体的约束(例如)时,类型约束很有用。Null <: A <: AnyA <: 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<:<[Null, Int]不符合Int并且没有隐含值。另一方面,Null确实符合String并且编译器会找到隐式参数。

顺便说一句,这是另一个相关的答案

于 2010-12-20T15:02:31.530 回答
0

Re : 'how' is this used - one place we are finding this useful is when dealing with java api mappings where null is commonplace, e.g. on jdbc prepared statements to nullable sql columns. The Optional internal model fields can be mapped:

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

Instead of the more verbose:

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