1
1
---
2
2
layout : tour
3
- title : Lower Type Bounds
3
+ title : 类型下界
4
4
5
5
discourse : false
6
6
@@ -13,3 +13,58 @@ language: zh-cn
13
13
next-page : inner-classes
14
14
previous-page : upper-type-bounds
15
15
---
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