繁体   English   中英

Traversable的继承和类型参数

[英]Inheritance and type parameters of Traversable

我正在研究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

我想在GenericTraversableTemplate使用@uncheckedVariance注释也与此有关吗? (这似乎是一种可能不安全的黑客,迫使事情发挥作用......)。

编辑 - 在这个问题中找到关于注释的一些有用的答案(这是因为GenericTraversableTemplate用于具有不同方差的可变和不可变集合)。

问题:当您查看层次结构时,您会看到Traversable继承HasNewBuilder两次(一次通过TraversableLike ,一次通过GenericTraversableTemplate ),但类型参数略有不同。 这是如何工作的? 为什么不同的类型参数不会导致错误?

原因是GenericTraversableTemplate特征中的CC参数。 与具有类型* (发音为“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]就是这样一种结果类型,正如我们计算的那样,它是一种类型* (它不需要参数)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM