2012-07-02 9 views
35

Was ist der Unterschied zwischen Iterator und Iterable in scala?Was ist die Beziehung zwischen Iterable und Iterator?

Ich dachte, dass Iterable eine Menge darstellt, die ich durchlaufen kann, und Iterator ist ein "Zeiger" auf eines der Elemente in der iterablen Menge.

Jedoch hat Iterator Funktionen wie forEach, map, foldLeft. Es kann zu Iterable über toIterable umgewandelt werden. Und zum Beispiel scala.io.Source.getLines kehrt Iterator, nicht Iterable.

Aber ich kann groupBy auf Iterator nicht tun und ich kann es auf Iterable tun.

Also, was ist die Beziehung zwischen diesen beiden, Iterator und Iterable?

Antwort

50

Kurz gesagt: Ein Iterator hat Zustand, während ein Iterable nicht.

Siehe API-Dokumentation für beide.

Iterable:

Ein Grundmerkmal für iterable Sammlungen.

Dies ist eine Basiseigenschaft für alle Scala-Sammlungen, die einen Iterator definieren, mit dem die Elemente der Sammlung einzeln durchlaufen werden. [...] Diese Eigenschaft implementiert Iterable foreach Verfahren durch durch alle Elemente Schritt Iterator.

Iterator:

Iteratoren sind Datenstrukturen, die eine Folge von Elemente iterieren ermöglichen. Sie haben eine hasNext-Methode zum Überprüfen, ob ein nächstes -Element verfügbar ist, und eine nächste Methode, die das nächste Element zurückgibt und es vom Iterator verwirft.

Ein Iterator ist änderbar: Die meisten Operationen ändern seinen Zustand. Während oft verwendet wird, um durch die Elemente einer Sammlung zu iterieren, kann auch verwendet werden, ohne von einer Sammlung gesichert werden (siehe Konstruktoren auf dem Companion-Objekt).

Mit einer Iterator können Sie eine Iteration stoppen und später fortsetzen, wenn Sie möchten. Wenn Sie versuchen, dies zu tun mit einem Iterable wird es vom Kopf wieder beginnen:

scala> val iterable: Iterable[Int] = 1 to 4 
iterable: Iterable[Int] = Range(1, 2, 3, 4) 

scala> iterable.take(2) 
res8: Iterable[Int] = Range(1, 2) 

scala> iterable.take(2) 
res9: Iterable[Int] = Range(1, 2) 

scala> val iterator = iterable.iterator 
iterator: Iterator[Int] = non-empty iterator 

scala> if (iterator.hasNext) iterator.next 
res23: AnyVal = 1 

scala> if (iterator.hasNext) iterator.next 
res24: AnyVal = 2 

scala> if (iterator.hasNext) iterator.next 
res25: AnyVal = 3 

scala> if (iterator.hasNext) iterator.next 
res26: AnyVal = 4 

scala> if (iterator.hasNext) iterator.next 
res27: AnyVal =() 

Beachten Sie, dass ich nicht take auf Iterator benutzt haben. Der Grund dafür ist, dass es schwierig zu verwenden ist. hasNext und next sind die einzigen zwei Methoden, die auf Iterator wie erwartet sind garantiert zu arbeiten.die Scaladoc wieder sehen:

Es ist von besonderer Bedeutung, zu beachten, dass, wenn nicht anders angegeben, man sollte nie einen Iterator verwenden, nachdem ein Verfahren auf sie anrufen. Die beiden wichtigsten Ausnahmen sind die einzigen abstrakten Methoden: next und hasNext.

Beide Methoden können beliebig oft aufgerufen werden, ohne den Iterator verwerfen zu müssen. Beachten Sie, dass sogar hasNext eine Mutation verursachen kann - , z. B. beim Iterieren aus einem Eingabestream, wo es blockiert, bis der Stream geschlossen wird oder eine Eingabe verfügbar wird.

Betrachten Sie dieses Beispiel für den sicheren und unsicheren Gebrauch:

def f[A](it: Iterator[A]) = { 
    if (it.hasNext) {   // Safe to reuse "it" after "hasNext" 
    it.next     // Safe to reuse "it" after "next" 
    val remainder = it.drop(2) // it is *not* safe to use "it" again after this line! 
    remainder.take(2)   // it is *not* safe to use "remainder" after this line! 
    } else it 
} 
+1

danke, mit dem Beispiel macht es vollkommen Sinn. –

+0

Odersky und Spoon haben einen guten Grund auf die Scala Kollektion geschrieben: siehe http://www.scala-lang.org/docu/files/collections-api/collections.html –

+0

Ich habe das in Scala 2.11.7 getestet, Iterator verhält sich ähnlich wie iterierbar, dh wenn Sie 'take (2)' zum zweiten Mal aufrufen, erhalten Sie immer noch 'List (1, 2)'. – qed

5

Eine andere Erklärung von Martin Odersky und Lex Löffel:

Es gibt einen wichtigen Unterschied zwischen dem foreach-Methode auf Iteratoren und die Gleiche Methode für traversierbare Sammlungen: Wenn foreach für einen Iterator aufgerufen wird, wird foreach den Iterator an seinem Ende belassen, wenn erledigt ist. Das nächste Aufrufen des nächsten Iterators wird daher mit einer NoSuchElementException fehlschlagen. Im Gegensatz dazu, foreach belässt Foreach die Anzahl der Elemente in der Sammlung unverändert (es sei denn, die übergebene Funktion fügt Elemente zu entfernen, aber das ist abgeraten, weil es zu überraschenden Ergebnissen führen kann).

Quelle: http://www.scala-lang.org/docu/files/collections-api/collections_43.html

Beachten Sie auch (dank Wei-Ching Lin für diesen Tipp) Iterator erweitert die TraversableOnce Eigenschaft während Iterable nicht der Fall ist.

0

Beachten Sie auch (dank Wei-Ching Lin für diesen Tipp) Iterator erweitert die TraversableOnce Eigenschaft während Iterable nicht der Fall ist.

In Scala 2.11 erweitert sowohl Iterator als auch Itarable die TraversableOnce-Eigenschaft.

Verwandte Themen