请解释 Option 的 orNull 方法的使用

发布于 2024-10-08 12:45:34 字数 189 浏览 1 评论 0原文

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

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

我对隐含的东西感到困惑。有人可以解释一下它的使用方法吗,最好是举个例子?

Scala's Option class has an orNull method, whose signature is shown below.

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

I'm bewildered by the implicit thing. Would somebody please explain how it can be used, ideally with an example?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

清醇 2024-10-15 12:45:34
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 已经设置,我们不想在特征的定义中限制它。因此,orNull 需要 A 是可为 null 类型的证据。该证据采用隐式变量的形式(因此名称为“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
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

To explain the implicit thing: orNull is a way of getting back from the Some|None idiom to Java's value|null idiom (which is, of course, bad). Now only AnyRef values (instances of classes) can accept a null value.

So what we would have liked is def orNull[A >: Null] = ..... But A is already set and we don't want to restrict it in the definition of the trait. Therefore, orNull expects an evidence that A is a nullable type. This evidence is in the form of an implicit variable (hence the name 'ev')

<:<[Null, A1] can be written as Null <:< A1 seeing it like this, it is similar to 'Null <: A1'. <:< is defined in Predef as well as the method that provides the implicit value named conforms.

I think the use of A1 is not strictly required here and is because orNull uses getOrElse (where the default given can be a super type of 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
囚你心 2024-10-15 12:45:34

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

orNull 有一个简单的实现:

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

根据此,不仅对于装箱的 null (Some(null)) 会返回 null,对于None(例如,如果调用None.get,将抛出异常)。

隐式参数检查装箱值是否可为空。

好的用法示例可以在 orNull 的注释:

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

orNull purpose is first of all in ensuring compatibility of Option with Java. Though usage of null is discouraged in Scala, some interfaces may expect to get nullable references.

orNull has a straightforward implementation:

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

According to this, null will be returned not only for boxed nulls (Some(null)), but also for None (e.g., if you call None.get, exception will be thrown).

Implicit parameter checks, if the boxed value is nullable.

Good usage example can be found right in the comments to orNull:

val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)
我们的影子 2024-10-15 12:45:34

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

Remember that in Scala primitive types and reference types are unified - but only reference types are nullable. The implicit simply allows the compiler to confirm that A1 is a reference type.

音盲 2024-10-15 12:45:34

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

所以我们想要的是 def
orNull[A >: Null] = ..... 但是 A 是
已经设置了,但我们不想设置
将其限制在定义中
特征。因此,orNull 期望
A 是可空类型的证据。
该证据的形式是
隐式变量(因此得名
'ev')

总之,当您希望在泛型类(例如 Option)上使用具有更具体约束(例如 orNull)的方法(例如 orNull)时,类型约束非常有用。 >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 cons[A]: A <:<一个。因此必须有一个 A ,其中 <:<[A, A] 符合 <:<[Null, Int]代码>.没有 A 可以满足此要求,因此编译器会抱怨缺少隐式值。

不过,对于

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

我们来说,还是幸运的。现在,编译器尝试查找 <:<[A, A] 符合 <:<[Null, String] 的 A。这适用于 A = String,因为 NullString 的子类型以及该类的 From 类型参数<:< 被定义为逆变)。

如前所述,考虑类型约束的最直观方法是像类型绑定一样读取它(即将其读取为 Null <: Int)。 Null 不符合 Int 并且 <:<[Null, Int] 没有隐式值。另一方面,Null 确实符合 String,编译器会找到隐式参数。

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

To understand why it is useful, IttayD provided a nice explanation:

So what we would have liked is def
orNull[A >: Null] = ..... But A is
already set and we don't want to
restrict it in the definition of the
trait. Therefore, orNull expects an
evidence that A is a nullable type.
This evidence is in the form of an
implicit variable (hence the name
'ev')

In summary, type constraints are useful when you want have methods (eg orNull) on a generic class (eg Option) with more specific constraints (eg Null <: A <: Any) than on the class itself (eg A <: Any).

This is another "feature" that is not built into the language but comes for free thanks to implicit parameters and variance annotations of type parameters. To understand this, look at the definition of <:<:

// from Predef      
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}

For

scala> Some(1).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
       Some(1).orNull

the compiler looks for an implicit value of type <:<[Null, Int] and will find the method def conforms[A]: A <:< A. So there has to be an A for which <:<[A, A] conforms to <:<[Null, Int]. There is no A for which this holds and as a result the compiler will complain about the missing implicit value.

However, for

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

we are lucky. Now, the compiler tries to find an A for which <:<[A, A] conforms to <:<[Null, String]. This works for A = String, because Null is a subtype of String and the From type parameter of the class <:< is defined as contravariant).

As mentioned, the most intuitive way to think about type constraints is reading it like a type bound (i.e. reading it as Null <: Int). Null does not conform to Int and there is no implicit value for <:<[Null, Int]. On the other hand, Null does conform to String and the compiler will find the implicit parameter.

By the way, here is another related answer.

戏舞 2024-10-15 12:45:34

回复:“如何”使用它 - 我们发现它有用的一个地方是在处理 java api 映射时,其中 null 很常见,例如,在 jdbc 准备好的语句到可为 null 的 sql 列上。可以映射Optional内部模型字段:

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

而不是更详细的:

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

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文