Scala Option类型上限不明白

时间:2015-04-27 20:42:32

标签: scala optional type-systems

我正在阅读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的类型为IntB类型为NothingNothing是所有其他类型的子类型。这意味着Option[Nothing]Option[Int]的子类型(因为协方差),对吗?

但是B >: A我们说B必须是超类型?!那么我们如何才能获得Int?这对我来说有点混乱......

任何人都在努力尝试澄清?

1 个答案:

答案 0 :(得分:8)

  

这意味着Option [Nothing]是Option [Int]的子类型(因为协方差),对吗?

正确。 Option[Nothing]Option[Int]

  

但是用B>:A我们说B必须是超类型?!那么我们怎样才能让Int回来?

它不一定是超级型。它只需要A作为下限。这意味着如果IntgetOrElse,您仍然可以将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上将CgetOrElse传递给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],可能会在其他地方引起错误。