我正在研究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
注释也与此有关吗? (这似乎是一种可能不安全的黑客,迫使事情发挥作用......)。
编辑 - 在this question中找到了关于注释的一些有用的答案(因为GenericTraversableTemplate
用于具有不同方差的可变和不可变集合。)
问题:当您查看层次结构时,您会看到Traversable
继承HasNewBuilder
两次(一次通过TraversableLike
,一次通过GenericTraversableTemplate
),但类型略有不同参数。这是如何工作的?为什么不同的类型参数不会导致错误?
答案 0 :(得分:16)
原因是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
类型参数如何获取自己的参数,但该参数未由声明中的任何其他类型参数定义?这是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]
是一个这样的结果类型,并且正如我们计算的那样,它是一种*
(它不需要参数)。