Scala的Option类有一个orNull
方法,其签名如下所示。
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
我被隐含的东西弄糊涂了。有人请说明如何使用它,理想情况下是一个例子吗?
答案 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
,则异常将被抛出)。
如果装箱值可以为空,则隐式参数检查。
中找到好用法示例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 = String
是Null
的子类型,而类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))