我正在研究Scala 2.8集合类的源代码.我对层次结构有疑问scala.collection.Traversable
.请查看以下声明:
package scala.collection trait Traversable[+A] extends TraversableLike[A, Traversable[A]] with GenericTraversableTemplate[A, Traversable] trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] with TraversableOnce[A] package scala.collection.generic trait HasNewBuilder[+A, +Repr] trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]
问题:为什么要使用类型参数进行Traversable
扩展- 为什么不呢?我试着尝试一个具有相同结构的小程序,并在我尝试将其更改为时收到一条奇怪的错误消息:GenericTraversableTemplate
[A, Traversable]
[A, Traversable[A]]
Traversable[A]
error: Traversable[A] takes no type parameters, expected: one
我猜这个@uncheckedVariance
注释的使用GenericTraversableTemplate
也与此有关吗?(这似乎是一种可能不安全的黑客,迫使事情发挥作用......).
编辑 - 在这个问题中找到关于注释的一些有用的答案(因为GenericTraversableTemplate
它用于具有不同方差的可变和不可变集合).
问题:当您查看层次结构时,您会看到Traversable
继承HasNewBuilder
两次(一次通过TraversableLike
和一次通过GenericTraversableTemplate
),但类型参数略有不同.这是如何工作的?为什么不同的类型参数不会导致错误?
原因是特征中的CC
参数GenericTraversableTemplate
.与具有种类*
(发音为"type")的普通类型参数不同,此参数具有类型* => *
(发音为"type to type").为了理解这意味着什么,你首先需要有一些关于种类的背景知识.
请考虑以下代码段:
val a: Int = 42
在这里,我们看到42
,这是一个价值.值具有固有类型.在这种情况下,我们的值是42
,类型是Int
.类型类似于包含许多值的类别.它说明了变量可能存在的值a
.例如,我们知道a
不能包含该值"foobar"
,因为该值具有类型String
.因此,值有点像第一级抽象,而类型比值高一级.
所以这就是问题:什么阻止我们更进一步?如果值可以有类型,为什么类型不能在它们上面有"东西"?那种"东西"被称为一种.类型是类型的类型,通用类别限制可以描述的类型.
让我们看一些具体的例子:
type String type Int type List[Int]
这些都是类型,它们都有种类*
.这是最常见的一种(这就是我们称之为"类型"的原因).在实践中,大多数类型都有这种类型.但是,有些人不这样做:
type List // note: compile error
这里我们有类型构造函数List
,但这次我们"忘记"指定它的类型参数.事实证明,这实际上是一种类型,但却是另一种类型.具体来说,* => *
.由于符号意味着暗示,这种类型描述了一种类型,它将另一种类型*
作为参数,从而产生一种新类型的*
结果.我们可以在第一个例子中看到这一点,我们将Int
类型(有类型*
)传递给List
类型构造函数(有类型* => *
),生成类型List[Int]
(有类型*
).
回过头来GenericTraversableTemplate
,让我们再看看声明:
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]]
注意CC
type参数如何获取它自己的参数,但该参数不是由声明中的任何其他类型参数定义的?这是Scala相当笨拙的说法CC
必须是善良的* => *
(就像我们之前的例子中a
的类型Int
一样)."正常"类型参数(例如A
)总是很好*
.通过强制CC
实物* => *
,我们有效地告诉编译器,可以替换此参数的唯一有效类型必须是它们本身的类型* => *
.从而:
type GenericTraversableTemplate[String, List] // valid! type GenericTraversableTemplate[String, List[Int]] // invalid!
请记住,List
是善良的* => *
(正是我们需要的CC
),但是List[Int]
有点*
,所以编译器拒绝它.
为了记录,GenericTraversableTemplate
本身有一种,特别是:(* x (* => *)) => *
.这意味着这GenericTraversableTemplate
是一种类型,它将两种类型作为参数 - 一种类型*
,另一种类型* => *
- 并产生一种类型的*
结果.在我们上面的例子中,GenericTraversableTemplate[String, List]
是一个这样的结果类型,并且正如我们计算的那样,它是一种类型*
(它不需要参数).