8

私はScala2.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分散が異なる可変コレクションと不変コレクションの両方に使用されるためです)。

質問:階層を見ると、2回(1回はviaと1回はvia )Traversable継承しますが、型パラメーターがわずかに異なります。これは正確にどのように機能しますか?異なるタイプのパラメーターがエラーを引き起こさないのはなぜですか?HasNewBuilderTraversableLikeGenericTraversableTemplate

4

1 に答える 1

17

その理由は、特性のCCパラメーターGenericTraversableTemplateです。種類(「type」と発音)を持つ通常の型パラメーターとは異なり*、このパラメーターにはtype * => *(「typetotype」と発音)があります。これが何を意味するのかを理解するには、まず種類について少し背景を知る必要があります。

次のスニペットについて考えてみます。

val a: Int = 42

ここに42であるが表示されます。値には固有の型があります。この場合、値は42で、タイプはIntです。タイプは、多くの値を含むカテゴリのようなものです。それは変数に可能な値について何かを言いますa。たとえば、値のタイプがであるため、a値を含めることはできません。したがって、値は抽象化の第1レベルのようなものですが、タイプは値の1レベル上です。"foobar"String

それで、ここに質問があります:これをさらに一歩進めることを私たちが妨げているのは何ですか?値が型を持つことができるのなら、なぜ型はそれらの上に「何か」を持つことができないのですか?その「何か」は種類と呼ばれます。種類はタイプであり、タイプは値であり、一般的なカテゴリはどの種類のタイプを記述できるかを制限します。

いくつかの具体的な例を見てみましょう。

type String
type Int
type List[Int]

これらはタイプであり、すべて種類があり*ます。これは最も一般的な種類です(これが「タイプ」と呼ばれる理由です)。実際には、ほとんどのタイプにこの種類があります。ただし、そうでないものもあります。

type List     // note: compile error

ここに型コンストラクターListがありますが、今回は型パラメーターを指定するのを「忘れました」。実は、これは実際にはタイプですが、別の種類の1つです。具体的には、* => *。表記が意味するように、この種類は、別の種類の種類*をパラメーターとして受け取り*、結果として新しい種類の種類を生成するタイプを表します。これは最初の例で見ることができます。ここでは、型(kindを持つ)を型コンストラクター(Intkindを持つ)に渡し、型(kindを持つ)を生成します。*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 (* => *)) => *。これは、2つのタイプ(1つは種類、もうGenericTraversableTemplate1つは種類)をパラメーターとして受け取り、結果として種類のタイプを生成するタイプであることを意味します。上記の例では、はそのような結果タイプの1つであり、計算したとおり、これは一種です(パラメーターを取りません)。** => **GenericTraversableTemplate[String, List]*

于 2010-04-29T04:57:25.223 に答える