簡體   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