Ответ 1
Короче: An Iterator
имеет состояние, а Iterable
- нет.
Смотрите документы API для обоих.
Базовый признак для повторяющихся коллекций.
Это базовый признак для всех коллекций Scala, которые определяют итератор метод для каждого элемента коллекции. [...] Эта черта реализует метод Iterable foreach путем степпинга через все элементы, использующие итератор.
Итераторы представляют собой структуры данных, которые позволяют выполнять итерацию по последовательности элементы. У них есть метод 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:
Особо важно отметить, что, если не указано иное, никогда нельзя использовать итератор после вызова метода на нем. Два наиболее важными исключениями являются также единственные абстрактные методы: следующий и 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 }