Scala之旅(TOUR OF SCALA)——类型下限(LOWER TYPE BOUNDS)

当类型上限限制了一个类型是另一个类型的子类时,类型下限则声明了一个类型是另一个类型的父类。这个表达式 B >: A 表示类型参数 B 或抽象类型 B 是类型 A 的父类。在大部分例子中, A 将成为类的类型参数, B 将成为方法的类型参数。

下面是一个有用的例子:

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

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

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

这个程序实现了一个单链表。 Nil 代表一个空的元素(一个空表)。class ListNode 是一个拥有 B 类型元素(头)的结点,而且指向列表的剩下的部分(尾)。 class Node 和它的子类因为有 +B 注解所以是协变。

然而,这个程序并不能通过编译因为在 prepend 方法中的参数 elem 的类型是声明为协变的 B 类型,也不能工作因为函数的参数类型是逆变的且返回类型才是协变的。

为了修复这个BUG,我们需要翻转 prepend 方法中的 elem 参数的变性。通过一个新的类型参数 U 作为 B 的类型下限来实现它。

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

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

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

现在我们可以实现下面的例子:

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

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

Node[bird]africanSwallow 赋值,但是可以接受 EuropeanSwallow 的实例。

Guess you like

Origin blog.csdn.net/cuipp0509/article/details/80360400