Я рассмотрел этот вопрос, но до сих пор не понимаю разницы между чертами Iterable и Traversable. Кто-нибудь может объяснить?
Я рассмотрел этот вопрос, но до сих пор не понимаю разницы между чертами Iterable и Traversable. Кто-нибудь может объяснить?
Ответы:
Проще говоря, итераторы сохраняют состояние, а обходные пути - нет.
TraversableИмеет один абстрактный метод: foreach. Когда вы вызываете foreach, коллекция будет кормить переданную функцию всеми элементами, которые она хранит, один за другим.
С другой стороны, у an Iterableесть абстрактный метод iterator, который возвращает Iterator. Вы можете позвонить nextпо принципу , Iteratorчтобы получить следующий элемент в момент вашего выбора. Пока вы этого не сделаете, он должен отслеживать, где он был в коллекции и что будет дальше.
Iterableрасширяется Traversable, так что я думаю, вы имеете в виду Traversables, которые не Iterables.
Traversableинтерфейса не требует сохранения состояния, в то время как соблюдение Iteratorинтерфейса требует.
Traversables, которые Iterableне сохраняют состояние итерации. Это Iteratorсозданный и возвращенный объект, Iterableкоторый сохраняет состояние.
Думайте об этом как о разнице между дутьем и сосанием.
Когда вы вызываете Traversables foreachили его производные методы, он будет передавать свои значения в вашу функцию по одному, поэтому он имеет контроль над итерацией.
С Iteratorвозвращением Iterableмысли вы высасываете из него значения, контролируя, когда переходить к следующему.
tl; dr Iterables , Traversablesкоторые могут создаватьIterators
Во-первых, знайте, что Iterableэто вычитание Traversable.
Во-вторых,
Traversableтребует реализации foreachметода, который используется всем остальным.
Iterableтребует реализации iteratorметода, который используется всем остальным.
Например, реализация findfor Traversableиспользует foreach(через for понимание) и выдает 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это более требовательная / мощная черта, поскольку вы можете легко реализовать foreachusing iterator, но не можете реализовать iteratorusing foreach.
Таким образом, Iterableпредоставляет способ приостановить, возобновить или остановить итерацию с помощью состояния Iterator. С участиемTraversable этом все или ничего (без исключений для управления потоком).
В большинстве случаев это не имеет значения, и вам понадобится более общий интерфейс. Но если вам когда-нибудь понадобится более индивидуальный контроль над итерацией, вам понадобится файл Iterator, который можно получить из файла Iterable.
Ответ Даниэля звучит хорошо. Дайте мне посмотреть, смогу ли я выразить это своими словами.
Таким образом, Iterable может предоставить вам итератор, который позволяет вам перемещаться по элементам по одному (используя next ()), а также останавливаться и идти в любое время. Для этого итератору необходимо сохранить внутренний «указатель» на позицию элемента. Но Traversable дает вам метод foreach для одновременного обхода всех элементов без остановки.
Что-то вроде Range (1, 10) должно иметь только 2 целых числа в качестве состояния Traversable. Но Range (1, 10) как Iterable дает вам итератор, который должен использовать 3 целых числа для состояния, одно из которых является индексом.
Учитывая, что Traversable также предлагает foldLeft, foldRight, его foreach должен перемещаться по элементам в известном и фиксированном порядке. Следовательно, можно реализовать итератор для Traversable. Например, def iterator = toList.iterator
Traversableв Scala 2.13 (она до сих пор хранится в качестве псевдонима для уходящегоIterableдо 2.14)