Я рассмотрел этот вопрос, но до сих пор не понимаю разницы между чертами Iterable и Traversable. Кто-нибудь может объяснить?
Я рассмотрел этот вопрос, но до сих пор не понимаю разницы между чертами Iterable и Traversable. Кто-нибудь может объяснить?
Ответы:
Проще говоря, итераторы сохраняют состояние, а обходные пути - нет.
Traversable
Имеет один абстрактный метод: foreach
. Когда вы вызываете foreach
, коллекция будет кормить переданную функцию всеми элементами, которые она хранит, один за другим.
С другой стороны, у an Iterable
есть абстрактный метод iterator
, который возвращает Iterator
. Вы можете позвонить next
по принципу , Iterator
чтобы получить следующий элемент в момент вашего выбора. Пока вы этого не сделаете, он должен отслеживать, где он был в коллекции и что будет дальше.
Iterable
расширяется Traversable
, так что я думаю, вы имеете в виду Traversable
s, которые не Iterable
s.
Traversable
интерфейса не требует сохранения состояния, в то время как соблюдение Iterator
интерфейса требует.
Traversable
s, которые Iterable
не сохраняют состояние итерации. Это Iterator
созданный и возвращенный объект, Iterable
который сохраняет состояние.
Думайте об этом как о разнице между дутьем и сосанием.
Когда вы вызываете Traversable
s foreach
или его производные методы, он будет передавать свои значения в вашу функцию по одному, поэтому он имеет контроль над итерацией.
С Iterator
возвращением Iterable
мысли вы высасываете из него значения, контролируя, когда переходить к следующему.
tl; dr Iterables
, Traversables
которые могут создаватьIterators
Во-первых, знайте, что Iterable
это вычитание Traversable
.
Во-вторых,
Traversable
требует реализации foreach
метода, который используется всем остальным.
Iterable
требует реализации iterator
метода, который используется всем остальным.
Например, реализация find
for 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
это более требовательная / мощная черта, поскольку вы можете легко реализовать foreach
using iterator
, но не можете реализовать iterator
using 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)