具体来说,请看getOrElse
。
Scala的Option
被定义为A
中的协变,如下所示:
sealed abstract class Option[+A] extends Product with Serializable {
self =>
@inline final def getOrElse[B >: A](default: => B): B =
if (isEmpty) default else this.get
}
getOrElse
的定义似乎意味着必须返回A
的超类型,这对我来说并不一定有意义。但事实上,它看起来像任何东西:子类型或超类型。
scala> class A
// defined class A
scala> class B extends A
// defined class B
scala> val optA: Option[A] = Option(null)
val optA: Option[A] = None
scala> optA.getOrElse(new B)
val res23: A = B@66a2c8e7
scala> class C extends B
// defined class C
scala> val optB: Option[B] = Option(null)
val optB: Option[B] = None
scala> optB.getOrElse(new A)
val res24: A = A@2a460bf
scala> optB.getOrElse(new C)
val res25: B = C@e87f97f
考虑到限制,这怎么可能?具体来说,考虑到optB.getOrElse(new C)
的约束,我不知道如何允许getOrElse
(它应该返回Option的类型参数的超类型)。
答案 0 :(得分:1)
不,它不是"一切顺利",仔细观察返回值的推断类型。
声明B >: A
表示:编译器将推断出最具体的类型B
,使getOrElse
的参数类型为B
,同时A
是B
的子类型。这是另一种说法:getOrElse
的返回类型是Option
的参数和fallback-argument的类型的最小上限。
您的实验证实了这一点:
scala> class A
scala> class B extends A
scala> class C extends B
scala> val optA: Option[A] = Option(null)
scala> optA.getOrElse(new B)
val res23: A = B@66a2c8e7 // LUB(A, B) = A
scala> val optB: Option[B] = Option(null)
scala> optB.getOrElse(new A)
val res24: A = A@2a460bf // LUB(B, A) = A, symmetric!
scala> optB.getOrElse(new C)
val res25: B = C@e87f97f // LUB(B, C) = B
最后一种情况当然是完全有效的,因为new C
的类型为C
,而C <: B
后,也是类型的元素{ {1}}。没有矛盾:B
是推断的返回类型,它不是最具体的参数类型B
(这将是default
,直接使用时大多没用。特别是,default.type
不一定是A
的子类型,这没有任何意义。
如果您系统地使用A,B,C的组合进行所有实验,您将获得以下返回类型:
default.type
这基本上是具有元素 | A B C
--+-----
A | A A A
B | A B B
C | A B C
的完全有序集合上的&#34;最大&#34; -function。
简单&amp;直观的规则是:编译器和标准库中方法的函数签名很难提供最具体的返回类型,并尽可能多地保留类型信息。