Scala: В чем разница между чертами Traversable и Iterable в коллекциях Scala? - PullRequest
91 голосов
/ 15 сентября 2011

Я посмотрел на этот вопрос , но все еще не понимаю разницу между чертами Iterable и Traversable.Может кто-нибудь объяснить?

Ответы [ 4 ]

217 голосов
/ 15 сентября 2011

Думайте об этом как о разнице между выдуванием и сосанием.

Когда вы вызываете Traversable s foreach или его производные методы, он отправляет свои значения в вашу функцию по одному - поэтому он может контролировать итерацию.

С Iterator, возвращаемым Iterable, вы высасываете из него значения, контролируя, когда перейти к следующему самостоятельно.

113 голосов
/ 15 сентября 2011

Проще говоря, итераторы сохраняют состояние, а traversables - нет.

A Traversable имеет один абстрактный метод: foreach.Когда вы вызываете foreach, , коллекция будет передавать переданной функции все элементы, которые она хранит, один за другим.

С другой стороны, Iterable имеет в качестве абстрактного методаiterator, который возвращает Iterator.Вы можете позвонить next на Iterator, чтобы получить следующий элемент в момент выбора.Пока вы этого не сделаете, он должен отслеживать, где он находился в коллекции, и что будет дальше.

20 голосов
/ 05 октября 2015

tl; др Iterables - это Traversables, которые могут производить состояния Iterators


Во-первых, знайте, что Iterable является вычитанием Traversable.

Второй,

  • Traversable требует реализации метода foreach, который используется всем остальным.

  • Iterable требует реализации метода iterator, который используется всем остальным.

Например, реализация find для Traversable использует foreach (через a для понимания) и выдает исключение BreakControl для остановки итерации, когда найден удовлетворительный элемент.

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
  }
}

Напротив, вычитание Iterable переопределяет эту реализацию и вызывает find для Iterator, который просто прекращает итерацию, когда элемент найден:

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
  }
}

Было бы неплохо не генерировать исключения для Traversable итерации, но это единственный способ частично итерировать при использовании только foreach.

С одной точки зрения, Iterable является более требовательной / мощной чертой, поскольку вы можете легко реализовать foreach, используя iterator, но вы не можете реально реализовать iterator, используя foreach.


В итоге, Iterable предоставляет способ приостановить, возобновить или остановить итерацию с помощью Iterator с сохранением состояния. С Traversable это все или ничего (без исключений для управления потоком).

В большинстве случаев это не имеет значения, и вам нужен более общий интерфейс. Но если вам когда-нибудь понадобится более настраиваемый контроль над итерацией, вам понадобится Iterator, который вы можете получить из Iterable.

0 голосов
/ 07 июня 2019

Ответ Даниэля звучит хорошо. Дай мне посмотреть, смогу ли я выразить это своими словами.

Таким образом, Iterable может предоставить вам итератор, который позволяет вам проходить элементы по одному (используя next ()), а также останавливаться и идти, как вам угодно. Для этого итератору необходимо сохранить внутренний «указатель» на позицию элемента. Но Traversable дает вам метод foreach для одновременного обхода всех элементов без остановки.

Что-то вроде Range (1, 10) должно иметь только 2 целых числа в качестве состояния Traversable. Но Range (1, 10) как итерируемый дает вам итератор, который должен использовать 3 целых числа для состояния, одно из которых является индексом.

Учитывая, что Traversable также предлагает foldLeft, foldRight, его foreach должен проходить элементы в известном и фиксированном порядке. Поэтому возможно реализовать итератор для Traversable. Например. def iterator = toList.iterator

...