我正在阅读Scala中的函数编程,在第04章中,作者自己实现了Option。现在,在定义函数getOrElse
时,他们使用上限将A
的类型限制为超类型(如果正确理解的话)
所以,定义是:
sealed trait Option[+A] {
def getOrElse[B >: A](default: => B): B = this match {
case None => default
case Some(a) => a
}
}
所以,当我们有像
这样的东西时val a = Some(4)
println(a.getOrElse(None)) => println prints a integer value
val b = None
println(b.getOrElse(Some(3)) => println prints a Option[Integer] value
a
的类型为Option[Int]
,因此A
的类型为Int
。 B
类型为Nothing
。 Nothing
是所有其他类型的子类型。这意味着Option[Nothing]
是Option[Int]
的子类型(因为协方差),对吗?
但是B >: A
我们说B
必须是超类型?!那么我们如何才能获得Int
?这对我来说有点混乱......
任何人都在努力尝试澄清?
答案 0 :(得分:8)
这意味着Option [Nothing]是Option [Int]的子类型(因为协方差),对吗?
正确。 Option[Nothing]
是Option[Int]
。
但是用B>:A我们说B必须是超类型?!那么我们怎样才能让Int回来?
它不一定是超级型。它只需要A
作为下限。这意味着如果Int
为getOrElse
,您仍然可以将A
传递给Int
。
但这并不意味着你无法传递子类的实例。例如:
class A
class B extends A
class C extends B
scala> Option(new B)
res196: Option[B] = Some(B@661f82ac)
scala> res196.getOrElse(new C)
res197: B = B@661f82ac
scala> res196.getOrElse(new A)
res198: A = B@661f82ac
scala> res196.getOrElse("...")
res199: Object = B@661f82ac
我仍然可以传递C
的实例,因为C
可以转发到B
。我也可以在继承树中传递一个更高的类型,而getOrElse
将返回该类型。如果我传递的类型与Option
中包含的类型无关,那么将推断出具有最小上限的类型。在上面的例子中,它是Any
。
那么为什么那里的下界呢?为什么没有:
def getOrElse[B <: A](default: => B): B
这不起作用,因为getOrElse
必须返回A
中包含的Option
或默认B
。但是,如果我们返回A
,而A
不是B
,则类型绑定无效。如果getOrElse
返回A
:
def getOrElse[B <: A](default: => B): A
这可以工作(如果它确实是这样定义的),但是你会受到类型边界的限制。因此,在上面的示例中,您只能在B
上将C
或getOrElse
传递给Option[B]
。无论如何,这不是标准库中的方式。
标准库getOrElse
允许您传递任何内容。假设你有Option[A]
。如果我们传递A
的子类型,那么它会向上转换为A
。如果我们通过A
,显然这没关系。如果我们传递其他类型,那么编译器会推断出两者之间的最小上限。在所有情况下,都符合类型绑定B >: A
。
因为getOrElse
允许你传递任何东西,所以很多人认为它非常棘手。例如,您可以:
val number = "blah"
// ... lots of code
val result = Option(1).getOrElse(number)
这将编译。我们只会有一个Option[Any]
,可能会在其他地方引起错误。