Der größte Teil der Komplexität der Implementierung des Collection-Frameworks ergibt sich aus der Tatsache, dass Scala im Gegensatz zu C # 's LINQ oder anderen Collection-Frameworks den "besten" Collection-Typ für Funktionen höherer Ordnung zurückgeben kann:
%Vor% Warum gilt dieses Prinzip nicht für Methoden wie seq
, par
, view
, force
?
Gibt es eine technische Einschränkung, die verhindert, dass es funktioniert?
Oder ist das Absicht / Design?
Wenn man bedenkt, dass LINQ grundsätzlich faul ist, ist Scalas Äquivalent ( view
, force
) nicht typsicherer (nur bei Verwendung der strikten Methoden), oder?
Es ist möglich, mehr Typinformationen in die parallelen Erfassungsklassen einzubetten, so dass Sie die Sammlung zurückbekommen, von der Sie ausgegangen sind, das stimmt. Dies würde bedeuten, dass nach dem Umwandeln eines List
in ein ParVector
durch Aufrufen von par
(in O (n), weil Elemente in den Vektor kopiert werden) und dann Aufruf von seq
, erneut ein List
. Um die Liste mit seq
zu erhalten, müssten Sie alle Elemente aus dem Vektor zurück in die Liste kopieren. Was stattdessen passiert, ist:
ParVector
wird wieder in ein Vector
konvertiert, wenn seq
aufgerufen wird - es wird in O (1) par
erneut für diesen Vektor auf und gibt Ihnen ein ParVector
in O (1), da sowohl der Vektor als auch der Parallelvektor dieselben zugrunde liegenden Daten Beachten Sie, dass eine Auflistung, z. B. eine Liste, neu strukturiert werden muss, wenn sie in eine parallele Sammlung umgewandelt wird. Andernfalls können die Operationen auf dieser Liste nicht effizient parallelisiert werden.
Somit müssen Sie beim Aufruf von par
und seq
nicht wiederholt für das Kopieren bezahlen - die Conversions werden viel effizienter. Da das primäre Ziel der parallelen Sammlungen die Steigerung der Effizienz war, wurde dies als wichtiger angesehen als das Prinzip des einheitlichen Rückgabetyps.
In Bezug auf den statischen Rückgabetyp einer Sammlungsmethode unterstützt C # das Überladen der LINQ-Erweiterungsmethoden ( Select
, Where
usw.) und wählt automatisch den spezifischsten im Bereich aus. So kann Seq.Select
eine Seq
zurückgeben, Enumerable.Select
kann eine Enumerable
usw. zurückgeben. Dies ist sehr ähnlich wie die spezifischste implizite Implementierung in Scala gewählt wird.
In Bezug auf den dynamischen Typ werden LINQ-Operationen als Erweiterungsmethoden implementiert, sodass keine dynamische Verteilung durchgeführt wird. % Co_de% gibt also (Seq as Enumerable).Select
zurück, nicht Enumerable
. In Scala werden Sammlungsmethodenaufrufe dynamisch versendet, sodass der dynamische Typ für Seq
, map
usw. gleich bleibt. Beide Ansätze haben Vorteile / Nachteile. Die einzige saubere Lösung für diese Art von Problem ist Multimethods IMHO und weder Sprache / Runtime unterstützt sie effizient.
Wie beim Laufzeitverhalten gibt LINQ immer eine träge ausgewertete Ansicht der Sammlung zurück. Es gibt keine Methode in der Ansicht, die eine Kollektion des Originaltyps magisch zurückgibt. Sie müssen manuell angeben, dass Sie ein Array verwenden möchten, zum Beispiel mit der Methode filter
. IMHO, das ist ein sauberer und einfacher Ansatz als der in Scala, und Lazy Collection-Operationen bilden besser als strikte, aber dies kostet einen extra Methodenaufruf, um eine strikte Sammlung für einzelne Collection-Operationen zu erhalten.
Tags und Links scala c# linq types collections