2012-03-31 2 views
2

Ich benutze Scala schon eine Weile und dachte, ich würde wirklich anfangen alles zu verstehen (naja, die meisten Dinge ...), aber ich fand mich durch eine Reihe von Methodendefinitionen in der Map-Klasse verwirrt. Ich weiß, wie foldLeft usw. funktioniert, aber was mich verwirrt, sind die Typparameter, die in den Kartenfunktionen benutzt werden. Lassen Sie uns foldLeft als Beispiel verwenden:Was sind die Regeln für den Fall, dass die Parameter des Trait/Class-Typs Vorrang vor den Parametern des Methodentyps haben?

foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B 

die Definition für den Map trait selbst nimmt zwei 'A' Typ-Parameter und 'B' (z Map [A ​​+ B]). Wenn ich einen Typparameter für eine Methode definiere, die denselben Namen wie einen der Typparameter für die Klasse/das Merkmal verwendet, überschreibt dies den Klassen-/Merkmalswert. Nehmen Sie diese Definition von Foo als Beispiel:

class Foo[A : Manifest, B : Manifest] { 
    def isAString() = manifest[A] == manifest[String] 
    def isAInt() = manifest[A] == manifest[Int] 
    def isBString() = manifest[B] == manifest[String] 
    def isBInt() = manifest[B] == manifest[Int] 
    def nowIsBString[B : Manifest] = manifest[B] == manifest[String] 
} 

scala> val f = new Foo[String,Int] 
f: Foo[String,Int] = [email protected] 

scala> f.isAString 
res290: Boolean = true 

scala> f.isAInt 
res291: Boolean = false 

scala> f.isBString 
res292: Boolean = false 

scala> f.isBInt 
res293: Boolean = true 

scala> f.nowIsBString[String] 
res294: Boolean = true 

scala> f.nowIsBString[Int] 
res295: Boolean = false 

So in der foldLeft Definition, 'B' stammt aus der Methodendefinition und 'A' kommt aus dem Zug Definition. Zum Beispiel:

val xm = Map("test" -> 1, "test2" -> 2) 

scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2 
foldFn: (Int, (String, Int)) => Int = <function2> 

scala> m.foldLeft(0)(foldFn) 
res298: Int = 3 

Dies wird als als ‚B‘ für die Funktion Streichhölzer ‚B‘ für das Merkmal erwartet, aber was ist, wenn ich den Typ, B 'für die Funktion String statt Int ändern:

scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2 
foldFn: (String, (String, String)) => java.lang.String = <function2> 

scala> m.foldLeft("")(foldFn) 
<console>:19: error: type mismatch; 
found : (String, (String, String)) => java.lang.String 
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String 
       m.foldLeft("")(foldFn) 

sie also die kv-Parameter (String, Int) ändern:

scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2 
foldFn: (String, (String, Int)) => java.lang.String = <function2> 

scala> m.foldLeft("")(foldFn) 
res299: java.lang.String = 12 

im Gegensatz zu meinem Foo Beispiel, in diesem Fall die die Karte 'B' Wert wird Vorrang vor den Funktionen Definition nehmen, aber nur für der kv-Parameter. Was hätte ich erwartet, ist eine foldLeft definiert, um zu sehen, wie folgt:

foldLeft[C] (z: C)(op: (C, (A, B)) => C): C 

, dass mehr für mich klar sein würde, aber es ist nicht diese Art und Weise definiert. Kennt also jemand die Regeln dafür, wann ein Methodenparameter einen Trait/Class-Parameter überschreibt und wann nicht?

+1

Aus irgendeinem Grund scheint ich nur die Antwort auf meine Frage zu finden, nachdem ich posten :) http://StackOverflow.com/Questions/8397684/Type-Parameter-of-Minbybf-ab-BImplicit-cmp-Orderingb-ab Allerdings würde ich gerne wissen, ob es Regeln gibt, um herauszufinden, wann dies passiert ist. – Mike

+0

'foldLeft' ist definiert auf' TraversableOnce'. Es ist 'A' Parameter ist der' TraversableOnce', nicht der von 'Map'. –

Antwort

1

Scala ist die gleiche wie Java in dieser Hinsicht und die folgende aus dem „Namen“ Kapitel the Java specification gilt:

Eine Erklärung d eines Typs n Schatten die Erklärungen von jeder benannten andere Typen genannt n, die an dem Punkt in ihrem Umfang sind, wo d ganzen Umfang der d auftritt.

So wird der Typparameter für eine Methode immer einen Klassen- oder Attributtyp mit demselben Namen schattieren. Ihr Foo Beispiel zeigt diese Tatsache.

Die scheinbare Gegen Sie im Fall von Map ‚s foldLeft sind zu sehen, ist nur an unpleasant artifact der aktuellen Version von Scaladoc, wie pointed out in den Antworten auf die Frage, die Sie verknüpft haben. foldLeft ist nicht in der Map Eigenschaft definiert, aber in TraversableOnce, wo es keinen Merkmalstyp-Parameter mit dem Namen B überhaupt gibt.

Im allgemeinen Shadowing der Typ Parameter eines Merkmals oder einer Klasse in einer Methode ist natürlich eine sehr schlechte Idee.

Verwandte Themen