Scala之旅-类型下界

Scala之旅-类型下界

类型下界(Lower Type Bounds)

与类型上界限制一个类型是另一个类型的子类型相反,类型下界声明一个类型是另一个类型的超类型。B >: A表示类型参数B或者抽象类型B是类型A的超类型。大部分情况下,A将会作为类的类型参数,B将会作为方法的类型参数。

下面是一个使用类型下界的例子:

trait Node[+B] {
  def prepend(elem: B): Unit
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
  def prepend(elem: B) = ListNode[B](elem, this)
  def head: B = h
  def tail = t
}

case class Nil[+B]() extends Node[B] {
  def prepend(elem: B) = ListNode[B](elem, this)
}

这个程序实现了一个单链列表。Nil代表一个空元素(也就是一个空列表)。类ListNode是一个包含一个类型为B的元素(head)和一个对列表其它元素的引用(tail)的节点。由于使用了+B,类Node和它的子类型都是协变的。

然而,由于在prepend中的参数elem是类型B的,而类型B是协变的,这个程序无法编译。这是因为函数的参数类型是逆变的,而结果类型是协变的。

为了修复这个问题,我们需要翻转prepend中的参数elem的类型的变性(variance)。我们通过引入一个新的类型参数U来实现,类型参数U以B作为类型下界。

trait Node[+B] {
  def prepend[U >: B](elem: U)
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
  def prepend[U >: B](elem: U) = ListNode[U](elem, this)
  def head: B = h
  def tail = t
}

case class Nil[+B]() extends Node[B] {
  def prepend[U >: B](elem: U) = ListNode[U](elem, this)
}

现在我们就可以执行如下程序了:

trait Mammal
case class AfricanSwallow() extends Mammal
case class EuropeanSwallow() extends Mammal

val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
val mammalList: Node[Mammal] = africanSwallowList
mammalList.prepend(new EuropeanSwallow)

Node[Mammal]可以被赋值为africanSwallowList,然后还能接受EuropeanSwallows。

参考资料

本文译自Tour Of Scala – Lower Type Bounds

上一篇:Scala之旅-类型上界

下一篇:Scala之旅-内部类

发表评论

电子邮件地址不会被公开。 必填项已用*标注