2012-07-02 6 views
35

В чем разница между Iterator и Iterable в scala?Какова связь между Iterable и Iterator?

Я думал, что Iterable представляет собой набор, который я могу прокручивать, и Iterator является «указателем» на один из элементов в итерируемом наборе.

Однако Iterator имеет следующие функции: forEach, map, foldLeft. Он может быть преобразован в Iterable через toIterable. И, например, scala.io.Source.getLines возвращает Iterator, а не Iterable.

Но я не могу сделать groupBy по телефону Iterator, и я могу это сделать на Iterable.

Итак, какова связь между этими двумя, Iterator и Iterable?

ответ

50

Вкратце: у Iterator есть состояние, а Iterable - нет.

См. Документы API для обоих.

Iterable:

Базовая черта для Iterable коллекций.

Это базовая черта для всех коллекций Scala, которые определяют метод итератора для того, чтобы каждый элемент пошагового элемента. [...] Эта черта реализует метод foreach Iterable, шаг за шагом через все элементы, использующие итератор.

Iterator:

итераторы представляют собой структуры данных, которые позволяют перебирать последовательность элементов. У них есть метод hasNext для проверки наличия следующего элемента и следующего метода, который возвращает следующий элемент и удаляет его из итератора.

Итератор изменчив: большинство операций на нем меняет свое состояние. В то время как он часто используется для итерации элементов коллекции, он может быть использован без поддержки какой-либо коллекции (см. конструкторы на сопутствующем объекте).

С помощью Iterator вы можете остановить итерацию и продолжить ее позже, если хотите. Если вы попытаетесь сделать это с Iterable он начнет с головы снова:

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

Обратите внимание, что я не использовал take на Iterator. Причина этого в том, что это сложно использовать. hasNext и next - это только два метода, которые гарантированно работают как ожидается на Iterator.Смотрите Scaladoc снова:

Это особенно важно отметить, что, если не указано иное, один никогда не должны использовать итератор после вызова метода на нем. Самые важные исключения - это единственные абстрактные методы: next и hasNext.

Оба эти метода могут быть вызваны любое количество раз, без необходимости отказаться от итератора. Обратите внимание, что даже hasNext может вызвать мутацию - , например, при итерации из входного потока, где он будет блокироваться до , поток закрыт или будет доступен какой-либо вход.

Рассмотрим пример для безопасного и небезопасного использования:

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

спасибо, с примером, это имеет смысл. –

+0

Odersky and Spoon написал хороший пример для классов коллекции Scala: см. http://www.scala-lang.org/docu/files/collections-api/collections.html –

+0

Я тестировал это в Scala 2.11.7, Итератор ведет себя аналогично итерабельному, а именно, когда вы вызываете 'take (2)' во второй раз, вы все равно получаете 'List (1, 2)'. – qed

5

Другое объяснение от Одерски и Lex Spoon:

Там важное различие между методом Еогеасп на итераторам и один и тот же метод для обходных коллекций: при вызове итератору foreach покидает итератор на своем конце, когда выполняется . Таким образом, вызов снова на том же итераторе завершится неудачей с NoSuchElementException. Напротив, при вызове в коллекции foreach оставляет количество элементов в коллекции неизменным (если переданная функция не добавляет к удалению элементов, но это обескуражен, так как это может привести к неожиданным результатам).

Источник: http://www.scala-lang.org/docu/files/collections-api/collections_43.html

Отметим также (благодаря Wei-Ching Lin для этого наконечника) Iterator расширяет TraversableOnce черту, а Iterable нет.

0

Отметим также (благодаря Вэй-Ching Lin для этого наконечника) итератора расширяет TraversableOnce черту, пока Iterable нет.

В scala 2.11 оба Iterator и Itarable расширяют TraversableOnce.

Смежные вопросы