Vererbung und Typ Parameter von Traversable

8

Ich untersuche den Quellcode der Scala 2.8 Collection Klassen. Ich habe Fragen zur Hierarchie von scala.collection.Traversable . Sehen Sie sich die folgenden Erklärungen an:

%Vor%

Frage: Warum erweitert Traversable GenericTraversableTemplate mit den Typparametern [A, Traversable] - warum nicht [A, Traversable[A]] ? Ich habe versucht, mit einem kleinen Programm mit der gleichen Struktur zu experimentieren und habe eine seltsame Fehlermeldung erhalten, als ich versucht habe, es in Traversable[A] zu ändern:

%Vor%

Ich nehme an, dass die Verwendung der @uncheckedVariance Annotation in GenericTraversableTemplate auch damit zu tun hat? (Das scheint eine Art potentiell unsicherer Hack zu sein, um Dinge zur Arbeit zu zwingen ...).

edit - einige nützliche Antworten auf die Annotation in diese Frage (weil GenericTraversableTemplate sowohl für veränderbare als auch für unveränderbare Sammlungen verwendet wird, die unterschiedliche Varianz haben).

Frage: Wenn Sie sich die Hierarchie ansehen, sehen Sie, dass Traversable zweimal HasNewBuilder erbt (einmal über TraversableLike und einmal über GenericTraversableTemplate ), aber mit etwas anderen Typparametern. Wie funktioniert das genau? Warum verursachen die verschiedenen Typparameter keinen Fehler?

    
Jesper 28.04.2010, 23:22
quelle

1 Antwort

16

Der Grund ist der CC Parameter im GenericTraversableTemplate Merkmal. Im Gegensatz zu einem normalen Typparameter, der die Art * hat (ausgesprochen "Typ"), hat dieser Parameter den Typ * => * (ausgesprochen "type to type"). Um zu verstehen, was das bedeutet, müssen Sie zuerst ein wenig Hintergrundwissen über Arten haben.

Betrachten Sie das folgende Snippet:

%Vor%

Hier sehen wir 42 , was ein Wert ist. Werte haben intrinsische Typen. In diesem Fall ist unser Wert 42 und der Typ Int . Ein Typ ist so etwas wie eine Kategorie, die viele Werte umfasst. Es sagt etwas über die Werte aus, die für die Variable a möglich sind. Zum Beispiel wissen wir, dass a den Wert "foobar" nicht enthalten kann, da dieser Wert den Typ String hat. Daher sind die Werte eine Art der ersten Abstraktionsebene, während die Typen eine Ebene über den Werten liegen.

Hier ist also die Frage: Was hält uns davon ab, diesen einen Schritt weiter zu gehen? Wenn Werte Typen haben können, warum können Typen nicht "etwas" über ihnen haben? Dieses "Etwas" wird als Art bezeichnet. Typen geben ein, welche Typen zu Werten gehören, generische Kategorien, die einschränken, welche Art von Typen beschrieben werden kann.

Sehen wir uns einige konkrete Beispiele an:

%Vor%

Dies sind Typen, und alle haben eine Art * . Dies ist die gebräuchlichste Art (weshalb wir es "Typ" nennen). In der Praxis haben die meisten Typen diese Art. Einige jedoch nicht:

%Vor%

Hier haben wir den Typkonstruktor List , aber dieses Mal haben wir "vergessen", seinen Typparameter anzugeben. Wie sich herausstellt, handelt es sich tatsächlich um einen Typ, der jedoch von anderer Art ist. Insbesondere * => * . Wie die Notation andeuten soll, beschreibt diese Art einen Typ, der einen anderen Typ der Art * als Parameter annimmt, wodurch ein neuer Typ von Art * erzeugt wird. Wir können dies im ersten Beispiel sehen, wo wir den Typ Int (welcher * hat) an den Konstruktor List übergeben haben (welcher * => * hat), was den Typ List[Int] (was kind * ).

Kehren wir zu GenericTraversableTemplate zurück, schauen wir uns noch einmal die Deklaration an:

%Vor%

Beachten Sie, dass der Parameter CC type einen eigenen Parameter verwendet, dieser Parameter jedoch von keinem anderen Typparameter in der Deklaration definiert ist? Das ist Scalas ziemlich ungeschickte Art zu sagen, dass CC vom Typ * => * sein muss (genauso wie a in unserem früheren Beispiel vom Typ Int sein muss). "Normal" -Typ-Parameter (zB A ) sind immer vom Typ * . Durch das Erzwingen von CC zur Art * => * teilen wir dem Compiler effektiv mit, dass die einzigen gültigen Typen, die diesen Parameter ersetzen können, selbst vom Typ * => * sein müssen. Also:

%Vor%

Denken Sie daran, List ist vom Typ * => * (genau das, was wir für CC brauchen), aber List[Int] hat kind * , so dass der Compiler es ablehnt.

Für den Datensatz hat GenericTraversableTemplate selbst eine Art, insbesondere: (* x (* => *)) => * . Dies bedeutet, dass GenericTraversableTemplate ein Typ ist, der zwei Typen als Parameter akzeptiert - einen vom Typ * , den anderen vom Typ * => * - und als Ergebnis einen Typ vom Typ * erzeugt. In unserem obigen Beispiel ist GenericTraversableTemplate[String, List] ein solcher Ergebnistyp, und wie wir berechnet haben, ist er vom Typ * (er benötigt keine Parameter).

    
Daniel Spiewak 29.04.2010, 04:57
quelle