Czy jest jakaś różnica pomiędzy :::
i ++
za łączeniem list w Scali?
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
Z dokumentacji wynika, że ++
jest bardziej ogólna, podczas gdy :::
jest List
specyficzna. Czy to drugie jest zapewnione, ponieważ jest używane w innych językach funkcjonalnych?
list
scala
concatenation
Luigi Plinge
źródło
źródło
:::
jest operatorem prefiks jak wszystkich metod zaczynając:
Odpowiedzi:
Dziedzictwo. Lista została pierwotnie zdefiniowana jako wyglądająca na języki funkcjonalne:
Oczywiście Scala ewoluowała inne kolekcje w sposób ad hoc. Kiedy pojawiła się wersja 2.8, kolekcje zostały przeprojektowane w celu maksymalnego ponownego wykorzystania kodu i spójnego interfejsu API, dzięki czemu można używać
++
do łączenia dowolnych dwóch kolekcji - a nawet iteratorów. Lista jednak zachowała swoich pierwotnych operatorów, oprócz jednego lub dwóch, które stały się przestarzałe.źródło
:::
na korzyść++
teraz? Użyj również+:
zamiast::
?::
jest przydatny ze względu na dopasowanie wzorca (patrz drugi przykład Daniela). Nie da się tego zrobić z+:
List
zamiastSeq
, równie dobrze możesz użyćList
metod idiomatycznych . Z drugiej strony utrudni to przejście na inny typ, jeśli kiedykolwiek będziesz tego chciał.::
i:::
), jak i bardziej ogólne operacje wspólne dla innych kolekcji. Nie usunęłbym żadnej operacji z języka.:+
i wypakowuje+:
obiekty.Zawsze używaj
:::
. Są dwa powody: wydajność i bezpieczeństwo typu.Wydajność
x ::: y ::: z
jest szybszy niżx ++ y ++ z
, ponieważ:::
ma właściwe skojarzenie.x ::: y ::: z
jest analizowany jakox ::: (y ::: z)
, który jest algorytmicznie szybszy niż(x ::: y) ::: z
(ten drugi wymaga O (| x |) więcej kroków).Wpisz bezpieczeństwo
Z
:::
możesz połączyć tylko dwaList
s. Dzięki++
niemu możesz dołączyć dowolną kolekcjęList
, co jest okropne:++
jest również łatwy do zmieszania z+
:źródło
x ::: y ::: z
należy go zastąpićList(x, y, z).flatten
. pastebin.com/gkx7Hpadx
iy
(z
nigdy nie jest iterowana, więc nie ma wpływu na czas wykonywania, dlatego lepiej jest dołączyć długą listę do krótszej niż na odwrót), ale asymptotyczna złożoność nie opowiada całej historii.x ::: (y ::: z)
iterujey
i dołączaz
, a następnie iterujex
i dołącza wyniky ::: z
.x
iy
oba są powtarzane raz.(x ::: y) ::: z
iterujex
i dołączay
, a następnie iteruje wynikx ::: y
i dołączaz
.y
wciąż jest powtarzany raz, alex
w tym przypadku jest powtarzany dwukrotnie.:::
działa tylko z listami, a++
można go używać z każdym przejściem. W obecnej implementacji (2.9.0),++
spada z powrotem na:::
jeśli argument jest równieżList
.źródło
Inną kwestią jest to, że pierwsze zdanie jest analizowane jako:
Natomiast drugi przykład jest analizowany jako:
Więc jeśli używasz makr, powinieneś się zachować ostrożność.
Poza tym,
++
dla dwóch list wywołuje się,:::
ale z większym obciążeniem, ponieważ prosi o wartość domyślną, aby mieć konstruktora z listy do listy. Ale mikrobenchmarki nie okazały niczego przydatnego w tym sensie, myślę, że kompilator optymalizuje takie wywołania.Mikro-Benchmarki po rozgrzaniu.
Jak powiedział Daniel C. Sobrai, możesz dołączyć zawartość dowolnej kolekcji do listy za pomocą
++
, podczas gdy za pomocą:::
możesz łączyć tylko listy.źródło