Was sind die Unterschiede zwischen Streams, Ansichten (SeqView) und Iteratoren in Scala? Das ist mein Verständnis:
- Sie sind alle faule Listen.
- Streams speichern die Werte zwischen.
- Iteratoren können nur einmal verwendet werden? Sie können nicht zum Anfang zurückkehren und den Wert erneut bewerten?
- Die Werte von View werden nicht zwischengespeichert, aber Sie können sie immer wieder auswerten?
Wenn ich also Heap-Speicherplatz sparen möchte, sollte ich Iteratoren (wenn ich die Liste nicht erneut durchlaufen möchte) oder Ansichten verwenden? Vielen Dank.
Antworten:
Erstens sind sie alle nicht streng . Dies hat eine bestimmte mathematische Bedeutung in Bezug auf Funktionen, bedeutet jedoch im Grunde, dass sie bei Bedarf statt im Voraus berechnet werden.
Stream
ist in der Tat eine faule Liste. Tatsächlich ist in Scala aStream
ein,List
dessen atail
istlazy val
. Nach der Berechnung bleibt ein Wert berechnet und wird wiederverwendet. Oder, wie Sie sagen, die Werte werden zwischengespeichert.Ein
Iterator
kann nur einmal verwendet werden, da es sich um einen Durchlaufzeiger in eine Sammlung handelt und nicht um eine Sammlung an sich. Das Besondere an Scala ist die Tatsache, dass Sie Transformationen wiemap
und anwenden könnenfilter
und einfach eine neue erhalten,Iterator
die diese Transformationen nur anwendet, wenn Sie nach dem nächsten Element fragen.Scala stellte früher Iteratoren bereit, die zurückgesetzt werden konnten, aber das ist im Allgemeinen sehr schwer zu unterstützen, und sie haben Version 2.8.0 nicht erstellt.
Ansichten sollen ähnlich wie eine Datenbankansicht angezeigt werden. Es ist eine Reihe von Transformationen, die man auf eine Sammlung anwendet, um eine "virtuelle" Sammlung zu erzeugen. Wie Sie sagten, werden alle Transformationen jedes Mal neu angewendet, wenn Sie Elemente daraus abrufen müssen.
Beide
Iterator
und Ansichten weisen hervorragende Speichereigenschaften auf.Stream
ist schön, aber in Scala besteht sein Hauptvorteil darin, unendliche Sequenzen zu schreiben (insbesondere Sequenzen, die rekursiv definiert sind). Sie können jedoch vermeiden, den gesamtenStream
Speicher zu behalten, indem Sie sicherstellen, dass Sie keinen Verweis darauf behaltenhead
(z. B. indem Sie dasdef
anstelle vonval
definieren, um es zu definierenStream
).Aufgrund der Nachteile von Ansichten sollte dies normalerweise
force
nach dem Anwenden der Transformationen geschehen oder als Ansicht beibehalten werden, wenn im Vergleich zur Gesamtgröße der Ansicht nur wenige Elemente erwartet werden, die jemals abgerufen werden.quelle
Iterator
ist auch ziemlich praktisch, um das Unendliche zu untersuchen, und ich bevorzuge sie im Allgemeinen Streams, wo dies möglich ist. Der eigentliche Vorteil von Streams besteht darin, dass zuvor aufgerufene Werte zwischengespeichert werden. Dies ist ein schwerwiegender Segen, wenn versucht wird, so etwas wie die Fibonacci-Sequenz zu implementieren, die anhand vorheriger Werte definiert wird.