Gibt es einen Unterschied zwischen :::
und ++
für die Verkettung von Listen in Scala?
scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> res0 == res1
res2: Boolean = true
Aus der Dokumentation geht hervor, dass ++
es allgemeiner ist, während :::
es List
spezifisch ist. Wird letzteres bereitgestellt, weil es in anderen funktionalen Sprachen verwendet wird?
list
scala
concatenation
Luigi Plinge
quelle
quelle
:::
ist ein Präfix-Operator wie alle Methoden beginnend mit:
Antworten:
Erbe. Die Liste wurde ursprünglich so definiert, dass sie nach funktionalen Sprachen aussieht:
Natürlich hat Scala andere Sammlungen ad-hoc weiterentwickelt. Als 2.8 herauskam, wurden die Sammlungen für maximale Code-Wiederverwendung und konsistente API neu gestaltet, sodass Sie zwei beliebige Sammlungen - und sogar Iteratoren -
++
verketten können . List musste jedoch seine ursprünglichen Operatoren behalten, abgesehen von einem oder zwei, die veraltet waren.quelle
:::
für++
jetzt? Auch+:
anstelle von verwenden::
?::
ist wegen des Mustervergleichs nützlich (siehe Daniel, zweites Beispiel). Sie können das nicht mit+:
List
anstelle von verwendenSeq
, können Sie auch idiomatischeList
Methoden verwenden. Auf der anderen Seite wird es schwieriger, zu einem anderen Typ zu wechseln , wenn Sie dies jemals wünschen.::
und:::
) als auch allgemeinere Operationen hat, die anderen Sammlungen gemeinsam sind. Ich würde keine Operation aus der Sprache streichen.:+
und Objektextraktoren+:
.Immer benutzen
:::
. Es gibt zwei Gründe: Effizienz und Typensicherheit.Effizienz
x ::: y ::: z
ist schneller alsx ++ y ++ z
, weil:::
richtig assoziativ ist.x ::: y ::: z
wird analysiert alsx ::: (y ::: z)
, was algorithmisch schneller ist als(x ::: y) ::: z
(letzteres erfordert O (| x |) mehr Schritte).Typensicherheit
Mit können
:::
Sie nur zweiList
s verketten . Mit können++
Sie jede Sammlung anhängenList
, was schrecklich ist:++
ist auch leicht zu verwechseln mit+
:quelle
x ::: y ::: z
sollten Sie diese durch ersetzenList(x, y, z).flatten
. pastebin.com/gkx7Hpadx
undy
(z
wird auf keinen Fall iteriert, hat also keinen Einfluss auf die Laufzeit, deshalb ist es besser, eine lange Liste an eine kurze anzuhängen, als umgekehrt), aber asymptotische Komplexität erzählt nicht die ganze Geschichte.x ::: (y ::: z)
iterierty
und hängt anz
, dann iteriertx
und hängt das Ergebnis von any ::: z
.x
undy
werden beide einmal iteriert.(x ::: y) ::: z
iteriertx
und hängt any
, dann iteriert das Ergebnis vonx ::: y
und hängt anz
.y
wird immer noch einmal iteriert,x
wird aber in diesem Fall zweimal iteriert.:::
funktioniert nur mit Listen,++
kann aber mit jedem Traversable verwendet werden. In der aktuellen Implementierung (2.9.0) wird++
zurückgegriffen,:::
wenn das Argument auch a istList
.quelle
Ein anderer Punkt ist, dass der erste Satz wie folgt analysiert wird:
Während das zweite Beispiel wie folgt analysiert wird:
Wenn Sie also Makros verwenden, sollten Sie vorsichtig sein.
Außerdem wird
++
für zwei Listen aufgerufen,:::
jedoch mit mehr Overhead, da nach einem impliziten Wert gefragt wird, um einen Builder von Liste zu Liste zu haben. Aber Mikrobenchmarks haben sich in diesem Sinne nicht als nützlich erwiesen. Ich denke, der Compiler optimiert solche Aufrufe.Mikro-Benchmarks nach dem Aufwärmen.
Wie Daniel C. Sobrai sagte, können Sie den Inhalt jeder Sammlung mit an eine Liste anhängen
++
, während:::
Sie damit nur Listen verketten können.quelle