Ich habe mir diese Frage angesehen , verstehe aber immer noch nicht den Unterschied zwischen iterierbaren und traversierbaren Merkmalen. Kann jemand erklären?
Ich habe mir diese Frage angesehen , verstehe aber immer noch nicht den Unterschied zwischen iterierbaren und traversierbaren Merkmalen. Kann jemand erklären?
Antworten:
Einfach ausgedrückt, Iteratoren behalten den Status bei, Traversables nicht.
A Traversable
hat eine abstrakte Methode : foreach
. Wenn Sie aufrufen foreach
, füttert die Sammlung die übergebene Funktion nacheinander mit allen Elementen, die sie behält.
Auf der anderen Seite hat ein Iterable
als abstrakte Methode iterator
, die ein zurückgibt Iterator
. Sie können rufen next
auf ein Iterator
das nächste Element zum Zeitpunkt Ihrer Wahl zu bekommen. Bis Sie dies tun, muss es verfolgen, wo es in der Sammlung war und was als nächstes kommt.
Iterable
erstreckt sich Traversable
, also denke ich, du meinst Traversable
s, die nicht Iterable
s sind.
Traversable
Schnittstelle erfordert nicht, den Status beizubehalten , während die Einhaltung der Iterator
Schnittstelle dies tut.
Traversable
s, Iterable
die keinen Iterationsstatus beibehalten. Es ist das, was von dem Iterator
geschaffen und zurückgegeben wird Iterable
, das den Zustand erhält.
Betrachten Sie es als den Unterschied zwischen Blasen und Saugen.
Wenn Sie ein Traversable
s foreach
oder seine abgeleiteten Methoden aufgerufen haben , werden seine Werte einzeln in Ihre Funktion eingeblendet, sodass es die Kontrolle über die Iteration hat.
Mit dem Iterator
von einem zurückgegebenen Iterable
Punkt saugen Sie die Werte heraus und steuern selbst, wann Sie zum nächsten wechseln müssen.
tl; dr Iterables
sind Traversables
, die Stateful produzieren könnenIterators
Erstens wissen, dass Iterable
das Subtrait von ist Traversable
.
Zweite,
Traversable
erfordert die Implementierung der foreach
Methode, die von allem anderen verwendet wird.
Iterable
erfordert die Implementierung der iterator
Methode, die von allem anderen verwendet wird.
Zum Beispiel die Implementierung von find
for- Traversable
Verwendungen foreach
(über ein zum Verständnis) und löst eine BreakControl
Ausnahme aus, um die Iteration anzuhalten, sobald ein zufriedenstellendes Element gefunden wurde.
trait TravserableLike {
def find(p: A => Boolean): Option[A] = {
var result: Option[A] = None
breakable {
for (x <- this)
if (p(x)) { result = Some(x); break }
}
result
}
}
Im Gegensatz dazu Iterable
überschreibt die Subtraktion diese Implementierung und ruft die find
auf Iterator
, die einfach aufhört zu iterieren, sobald das Element gefunden wurde:
trait Iterable {
override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
iterator.find(p)
}
trait Iterator {
def find(p: A => Boolean): Option[A] = {
var res: Option[A] = None
while (res.isEmpty && hasNext) {
val e = next()
if (p(e)) res = Some(e)
}
res
}
}
Es wäre schön, keine Ausnahmen für die Traversable
Iteration auszulösen, aber dies ist die einzige Möglichkeit, teilweise zu iterieren, wenn nur verwendet wird foreach
.
Aus einer Perspektive, Iterable
ist die anspruchsvolleren / mächtig Zug, wie Sie leicht umsetzen können foreach
mit iterator
, aber man kann nicht wirklich implementieren iterator
verwenden foreach
.
Zusammenfassend Iterable
bietet es eine Möglichkeit, die Iteration über einen Stateful anzuhalten, fortzusetzen oder zu stoppen Iterator
. Mit Traversable
ist es alles oder nichts (ohne Ausnahmen für die Flusskontrolle).
Meistens spielt es keine Rolle, und Sie möchten die allgemeinere Benutzeroberfläche. Wenn Sie jedoch jemals eine individuellere Kontrolle über die Iteration benötigen Iterator
, benötigen Sie eine , die Sie von einer abrufen können Iterable
.
Daniels Antwort klingt gut. Lassen Sie mich sehen, ob ich es in meine eigenen Worte fassen kann.
Ein Iterable kann Ihnen also einen Iterator geben, mit dem Sie die Elemente einzeln (mit next ()) durchlaufen und anhalten und loslegen können, wie Sie möchten. Dazu muss der Iterator einen internen "Zeiger" auf die Position des Elements halten. Ein Traversable bietet Ihnen jedoch die Möglichkeit, alle Elemente gleichzeitig zu durchlaufen, ohne anzuhalten.
So etwas wie Range (1, 10) muss nur 2 Ganzzahlen als Status eines Traversable haben. Mit Range (1, 10) als Iterable erhalten Sie jedoch einen Iterator, der 3 Ganzzahlen für den Status verwenden muss, von denen eine ein Index ist.
In Anbetracht dessen, dass Traversable auch foldLeft und foldRight bietet, muss foreach die Elemente in einer bekannten und festen Reihenfolge durchlaufen. Daher ist es möglich, einen Iterator für ein Traversable zu implementieren. ZB def iterator = toList.iterator
Traversable
in Scala 2,13 (es immer noch als deprecated alias für gehalten wird ,Iterable
bis 2.14)