当前位置:  开发笔记 > 编程语言 > 正文

Traversable的继承和类型参数

如何解决《Traversable的继承和类型参数》经验,为你挑选了1个好方法。

我正在研究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),但类型参数略有不同.这是如何工作的?为什么不同的类型参数不会导致错误?



1> Daniel Spiew..:

原因是特征中的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]]

注意CCtype参数如何获取它自己的参数,但该参数不是由声明中的任何其他类型参数定义的?这是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]是一个这样的结果类型,并且正如我们计算的那样,它是一种类型*(它不需要参数).

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有