2016-06-20 7 views
6

Im folgenden Beispiel kann f3 eine Iterable [Array [Int]]Lokale Zuordnung wirkt sich auf den Typ aus?

def f3(o:Iterable[Iterable[Any]]):Unit = {} 

    f3(Iterable(Array(123))) // OK. Takes Iterable[Array[Int]] 

nehmen, aber wenn ich die Iterable [Array [Int]] zu einer lokalen Variablen zuweisen, kann es nicht:

val v3 = Iterable(Array(123)) 
    f3(v3) // Fails to take Takes Iterable[Array[Int]] 

mit dem Fehler:

Error:(918, 10) type mismatch; 
    found : Iterable[Array[Int]] 
    required: Iterable[Iterable[Any]] 
    f3(x) 

Was die Fudge? Warum funktioniert das erste Beispiel, aber nicht die Sekunden? Es scheint, etwas zu haben, mit verschachtelten Generika zu tun:

def f(o:Iterable[Any]):Unit = {} 
    f(Array(123)) 
    val v1 = Array(123) 
    f(v1) // OK 

    def f2(o:Iterable[Any]):Unit = {} 
    f2(Iterable(Array(123))) 
    val v2 = Array(123) 
    f(v2) // OK 

Mit scala.2.11

+0

Warum 'Iterable [Alles]'? Genauso wenig wie Generika/Typ. – cchantep

+0

Any ist die gemeinsame Schnittstelle des Objekts, das ich in meinen Sammlungen brauche. In einigen Kontexten wird Scala sauer, wenn Sie keinen Parametertyp angeben und statt dessen nichts zurückgibt, insbesondere wenn Sie Generika zurückgeben. – user48956

+0

Vor allem, wenn Sie 'Any' benötigen, gibt es ein Designproblem – cchantep

Antwort

6

Zunächst einmal ist es wichtig, dass Array nicht Iterable erstreckt (weil es sich um eine Java-Typ ist). Stattdessen gibt es eine implizite Konvertierung von Array[A] zu Iterable[A], so dass die erwarteten Typen von Bedeutung sind.

Im ersten Fall: Iterable(Array(123)) ist ein Argument zu f3 und ist daher typeChecked mit erwarteten Typ Iterable[Iterable[Any]]. So wird Array(123) mit dem erwarteten Typ Iterable[Any] typechecked. Nun, sein tatsächlicher Typ ist Array[Int] und der Compiler fügt die Konvertierung ein (weil Iterable[Int] konform zu Iterable[Any] ist). Also das ist eigentlich Iterable(array2iterable(Array(123)) (ich erinnere mich nicht an den genauen Namen).

Im zweiten Fall f3 hat den Typ Iterable[Array[Int]]: Es gibt nichts, um die implizite Umwandlung in der val f3 = ... Zeile auszulösen, richtig? Und es gibt keine implizite Konvertierung von Iterable[Array[Int]] zu Iterable[Iterable[Int]] (oder allgemeiner von Iterable[A] zu Iterable[B], wenn es eine implizite Konvertierung von A zu B gibt), so dass die nächste Zeile nicht kompiliert werden kann. Sie könnten diese Umwandlung selbst schreiben, aber es würde nicht helfen, z.B. um Array[Array[Int]] zu Iterable[Iterable[Int]] zu konvertieren.

Und natürlich, wenn Sie Iterable[Any] verwenden, gibt es wieder nichts, um die implizite Konvertierung auszulösen!

+0

Dies erklärt nicht, warum im ersten Fall explizite Konvertierung geschieht, aber nein, es Sekunde: sein kann„dort von ... bis ... keine implizite Konvertierung ist“ richtig, aber warum funktioniert dann der erste Fall? – Dima

+0

@Dima Der erste Fall funktioniert, weil es eine implizite Umwandlung von 'Array [Int]' nach 'Iterable [Int]' gibt. Da wir also ein Array verwenden, in dem ein iterabler Wert angegeben wird, kann die Konvertierung verwendet werden. Im zweiten Fall die Zeile 'val v3 = Iterable (Array (123))' erwartet nicht 'Iterable [Int]' überall, so dass keine implizite Konvertierung benötigt wird, um für diese Linie zu arbeiten. Wir bekommen dann ein Problem in der nächsten Zeile, aber dann ist es zu spät, um eine implizite Umwandlung um 'Array (123)' hinzuzufügen (weil das bereits in der vorherigen Zeile ausgeführt wurde). Im besten Fall konnten wir einen um 'v3' herumlaufen, aber wie Alexey sagt, gibt es keinen passenden. – sepp2k

+0

@Dima Er ... es tut? "So wird Array (123) mit dem erwarteten Typ Iterable [Any] typenchecked. Nun, sein tatsächlicher Typ ist Array [Int] und der Compiler fügt die Konvertierung ein (weil Iterable [Int] Iterable [Any] entspricht)." –

4

Dies hat mit der Art und Weise zu tun, die Inferenz/Vereinigung in Scala funktioniert.

Wenn Sie eine Variable definieren und die Art auslassen, gilt Scala die spezifischste Art möglich:

scala> val v1 = Iterable(Array(123)) 
v1: Iterable[Array[Int]] = List(Array(123)) 

Wenn Sie jedoch den erwarteten Typen angeben (zB durch den Wert auf eine Funktion mit einem definierten vorbei Parametertyp) Scala vereint die angegebenen Parameter mit dem erwarteten Typ (wenn möglich):

scala> val v2 : Iterable[Iterable[Any]] = Iterable(Array(123)) 
v2: Iterable[Iterable[Any]] = List(WrappedArray(123)) 

Da Int ist ein Subtyp von Any, Vereinigung auftritt, und der Code läuft gut.

Wenn Sie möchten, dass Ihre Funktion alles akzeptiert, was ein Untertyp von Any ist (ohne Scalas Unification-Hilfe), müssen Sie dieses Verhalten explizit definieren.

Edit:

Während das, was ich sage, teilweise wahr ist, siehe @ AlexyRomanov Antwort für eine richtige Einschätzung. Es scheint, dass die „Vereinigung“ zwischen Array und Iterable ist wirklich eine implizite Konvertierung genannt wird, wenn Sie Iterable(Array(123)) als Parameter (siehe die Wirkung dieses in meiner Erklärung von v2) übergeben.

Angenommen, Sie haben ein wenig Code, wo der Compiler den Typ B erwartet, aber stattdessen den Typ A findet. Bevor ein Fehler ausgegeben wird, prüft der Compiler eine Sammlung impliziter Konvertierungsfunktionen auf eine mit dem Typ A => B. Wenn der Compiler eine zufriedenstellende Konvertierung findet, wird die Konvertierung automatisch (und im Hintergrund) ausgeführt.

Der Grund f3 nicht v1 mag, ist, weil es zu spät ist eine implizite Konvertierung auf den inneren Array[Int] und keine bestehende implizite Konvertierung für Iterable[Array[Int]] => Iterable[Iterable[Int]] existiert zu nennen, obwohl es trivial zu implementieren wäre, wie ich weiter unten zeigen:

scala> implicit def ItAr2ItIt[T](ItAr: Iterable[Array[T]]): Iterable[Iterable[T]] = ItAr.map(_.toIterable) 
ItAr2ItIt: [T](ItAr: Iterable[Array[T]])Iterable[Iterable[T]] 

scala> def f3(o:Iterable[Iterable[Any]]):Unit = println("I like what I see!") 
f3: (o: Iterable[Iterable[Any]])Unit 

scala> val v3 = Iterable(Array(123)) 
v3: Iterable[Array[Int]] = List(Array(123)) 

scala> f3(v3) 
I like what I see! 
Verwandte Themen