2012-07-02 14 views
35

Jaka jest różnica między Iterator i Iterable w scala?Jaka jest relacja między Iterable a Iterator?

Myślałem, że Iterable reprezentuje zestaw, który mogę iterować, a Iterator jest "wskaźnikiem" do jednego z elementów w zestawie iterowalnym.

Jednak funkcje Iterator mają następujące funkcje: forEach, map, foldLeft. Można go przekonwertować na Iterable przez toIterable. Na przykład scala.io.Source.getLines zwraca Iterator, a nie Iterable.

Ale nie mogę wykonać groupBy na Iterator i mogę to zrobić na Iterable.

Jaka jest relacja między tymi dwoma, Iterator i Iterable?

Odpowiedz

50

W skrócie: Iterator ma stan, natomiast Iterable nie.

Zobacz dokumentację interfejsu API dla obu.

Iterable:

Cechą bazą dla kolekcji iterable.

Jest to podstawowa cecha dla wszystkich kolekcji Scala, które definiują metodę iteratora , aby krok po kroku przenosić elementy kolekcji. [...] Ta cecha implementuje metodę foreach Iterable, wprowadzając przez wszystkie elementy za pomocą iteratora.

Iterator:

Iterators są struktury danych, które pozwalają na iteracyjnego sekwencję elementów. Mają metodę hasNext do sprawdzenia, czy dostępny jest następny element , i następną metodę, która zwraca następny element i odrzuca go z iteratora.

Iterator jest zmienny: większość operacji na nim zmienia swój stan. Podczas gdy jest często wykorzystywany do iteracji elementów kolekcji, można go również używać bez konieczności tworzenia kopii zapasowej przez dowolny zbiór (patrz konstruktory w obiekcie towarzyszącym).

Dzięki Iterator możesz zatrzymać iterację i kontynuować ją później, jeśli chcesz. Jeśli spróbujesz zrobić to z Iterable rozpocznie się od głowy znowu:

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 =() 

uwaga, że ​​nie używałem take na Iterator. Powodem tego jest to, że jest trudny w użyciu. hasNext i next to jedyne dwie metody, które działają zgodnie z oczekiwaniami na Iterator.Zobacz kolejny Scaladoc:

Jest to szczególnie ważne, aby pamiętać, że o ile nie zaznaczono inaczej, nigdy nie należy używać iterator po wywołaniu metody na nim. Dwa najważniejsze wyjątki to również jedyne abstrakcyjne metody: next i hasNext.

Obie te metody można wywoływać dowolną liczbę razy bez konieczności odrzucania iteratora przez . Zauważ, że nawet hasNext może powodować mutację - , na przykład podczas iteracji ze strumienia wejściowego, gdzie będzie blokować do momentu zamknięcia strumienia lub udostępnienia niektórych danych wejściowych.

Rozważmy następujący przykład dla bezpiecznego i niebezpiecznego użycia:

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

dzięki, na przykład, ma to sens. –

+0

Odersky i Spoon napisali dobry primer na temat klas kolekcji Scala: zobacz http://www.scala-lang.org/docu/files/collections-api/collections.html –

+0

Przetestowałem to w Scali 2.11.7, iterator zachowuje się podobnie do iteracji, a mianowicie, gdy po raz drugi wywołujesz 'take (2)', nadal otrzymujesz 'List (1, 2)'. – qed

5

Innym wyjaśnieniem od Martin Odersky i Lex Łyżka:

Istnieje istotna różnica między metodą foreach na iteratory i tym ta sama metoda na kolekcjach przenośnych: Po wywołaniu do iteratora, foreach opuści iterator na jego końcu, gdy zostanie zrobione . Ponowne wywołanie następnego na tym samym iteratorze zakończy się niepowodzeniem z powodu wyjątku NoSuchElementException: . Natomiast po wywołaniu w kolekcji, foreach pozostawia niezmienioną liczbę elementów w kolekcji (chyba że przekazana funkcja dodaje do usuwania elementów, ale jest to zniechęcone, ponieważ może to prowadzić do zaskakujących wyników).

Źródło: http://www.scala-lang.org/docu/files/collections-api/collections_43.html

Uwaga również (dzięki Wei-Lin Ching tej końcówce) Iterator rozszerza cechę TraversableOnce podczas Iterable nie.

0

Uwaga również (dzięki Wei-Lin Ching dla tej końcówki) Iterator rozszerza cechę TraversableOnce podczas iterowalny nie.

W wersji 2.11 zarówno Iterator, jak i Itarable rozszerzają TraversableOnce cecha.

Powiązane problemy