Scala: в чем разница между проходимыми и повторяемыми признаками в коллекциях Scala?


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

3 85

3 ответа:

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

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

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

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

когда у вас есть вызов Traversables foreach, или его производные методы, он будет выдувать свои значения в вашу функцию по одному за раз-так что он имеет контроль над итерацией.

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

tl; drIterables are Traversables что можно производить с учетом состояния Iterators


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

второе,

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

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

например, имплементация find на Traversable использует foreach (через Для понимания) и бросает!--14--> исключение для остановки итерации после того, как удовлетворительный элемент был найден.

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 предоставляет способ приостановить, возобновить или остановить итерацию с помощью stateful Iterator. С Traversable, это все или ничего (без исключений для управления потоком).

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