类型上界 将类型限制为另一种类型的子类型,而 类型下界 将类型声明为另一种类型的超类型。 术语 B >: A 表示类型参数 B 或抽象类型 B 是类型 A 的超类型。 在大多数情况下,A 将是类的类型参数,而 B 将是方法的类型参数。

    下面看一个适合用类型下界的例子:

    1. trait Node[+B] {
    2. def prepend(elem: B): Node[B]
    3. }
    4. case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
    5. def prepend(elem: B): ListNode[B] = ListNode(elem, this)
    6. def head: B = h
    7. def tail: Node[B] = t
    8. }
    9. case class Nil[+B]() extends Node[B] {
    10. def prepend(elem: B): ListNode[B] = ListNode(elem, this)
    11. }

    该程序实现了一个单链表。 Nil 表示空元素(即空列表)。 class ListNode 是一个节点,它包含一个类型为 B (head) 的元素和一个对列表其余部分的引用 (tail)。 class Node 及其子类型是协变的,因为我们定义了 +B

    但是,这个程序 不能 编译,因为方法 prepend 中的参数 elem变的 B 类型。 这会出错,因为函数的参数类型是变的,而返回类型是变的。

    要解决这个问题,我们需要将方法 prepend 的参数 elem 的型变翻转。 我们通过引入一个新的类型参数 U 来实现这一点,该参数具有 B 作为类型下界。

    1. trait Node[+B] {
    2. def prepend[U >: B](elem: U): Node[U]
    3. }
    4. case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
    5. def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
    6. def head: B = h
    7. def tail: Node[B] = t
    8. }
    9. case class Nil[+B]() extends Node[B] {
    10. def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
    11. }

    现在我们像下面这么做:

    1. trait Bird
    2. case class AfricanSwallow() extends Bird
    3. case class EuropeanSwallow() extends Bird
    4. val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
    5. val birdList: Node[Bird] = africanSwallowList
    6. birdList.prepend(new EuropeanSwallow)

    可以为 Node[Bird] 赋值 africanSwallowList,然后再加入一个 EuropeanSwallow