11---
22layout : tour
3- title : Lower Type Bounds
3+ title : 类型下界
44
55discourse : false
66
@@ -13,3 +13,58 @@ language: zh-cn
1313next-page : inner-classes
1414previous-page : upper-type-bounds
1515---
16+
17+ [ 类型上界] ( upper-type-bounds.html ) 将类型限制为另一种类型的子类型,而 * 类型下界* 将类型声明为另一种类型的超类型。 术语 ` B >: A ` 表示类型参数 ` B ` 或抽象类型 ` B ` 是类型 ` A ` 的超类型。 在大多数情况下,` A ` 将是类的类型参数,而 ` B ` 将是方法的类型参数。
18+
19+ 下面看一个宜用类型下届的例子:
20+
21+ ``` tut:fail
22+ trait Node[+B] {
23+ def prepend(elem: B): Node[B]
24+ }
25+
26+ case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
27+ def prepend(elem: B): ListNode[B] = ListNode(elem, this)
28+ def head: B = h
29+ def tail: Node[B] = t
30+ }
31+
32+ case class Nil[+B]() extends Node[B] {
33+ def prepend(elem: B): ListNode[B] = ListNode(elem, this)
34+ }
35+ ```
36+
37+ 该程序实现了一个单链表。 ` Nil ` 表示空元素(即空列表)。 ` class ListNode ` 是一个节点,它包含一个类型为 ` B ` (` head ` ) 的元素和一个对列表其余部分的引用 (` tail ` )。 ` class Node ` 及其子类型是协变的,因为我们定义了 ` +B ` 。
38+
39+ 但是,这个程序 _ 不能_ 编译,因为方法 ` prepend ` 中的参数 ` elem ` 是* 协* 变的 ` B ` 类型。 这会出错,因为函数的参数类型是* 逆* 变的,而返回类型是* 协* 变的。
40+
41+ 要解决这个问题,我们需要将方法 ` prepend ` 的参数 ` elem ` 的型变翻转。 我们通过引入一个新的类型参数 ` U ` 来实现这一点,该参数具有 ` B ` 作为类型下界。
42+
43+ ``` tut
44+ trait Node[+B] {
45+ def prepend[U >: B](elem: U): Node[U]
46+ }
47+
48+ case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
49+ def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
50+ def head: B = h
51+ def tail: Node[B] = t
52+ }
53+
54+ case class Nil[+B]() extends Node[B] {
55+ def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
56+ }
57+ ```
58+
59+ 现在我们像下面这么做:
60+ ``` tut
61+ trait Bird
62+ case class AfricanSwallow() extends Bird
63+ case class EuropeanSwallow() extends Bird
64+
65+
66+ val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
67+ val birdList: Node[Bird] = africanSwallowList
68+ birdList.prepend(new EuropeanSwallow)
69+ ```
70+ 可以为 ` Node[Bird] ` 赋值 ` africanSwallowList ` ,然后再加入一个 ` EuropeanSwallow ` 。
0 commit comments