Я розглянув це питання, але досі не розумію різниці між ознаками, які можна відмінити і відміняти. Може хтось пояснить?
Я розглянув це питання, але досі не розумію різниці між ознаками, які можна відмінити і відміняти. Може хтось пояснить?
Відповіді:
Простіше кажучи, ітератори зберігають стан, траверси - ні.
Traversable
Має один абстрактний метод: foreach
. Коли ви телефонуєте foreach
, колекція передаватиме переданій функції всі елементи, які вона зберігає, один за одним.
З іншого боку, 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
для Traversable
використання foreach
(через розуміння) та викид для 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
.
Відповідь Даніеля звучить добре. Дозвольте мені побачити, чи можу я сказати це своїми словами.
Таким чином, Ітерабельний може дати вам ітератор, який дозволяє вам перетинати елементи один за одним (використовуючи next ()), а також зупинятися та їхати як завгодно. Для цього ітератору необхідно зберегти внутрішній «покажчик» на позицію елемента. Але Траверсай дає вам метод, передбачити, щоб пройти всі елементи одразу, не зупиняючись.
Щось на зразок діапазону (1, 10) повинно бути лише 2 цілих числа, як стан як прохідний. Але Діапазон (1, 10) як Ітерабельний дає вам ітератор, який повинен використовувати 3 цілі числа для стану, одне з яких - індекс.
Зважаючи на те, що Traversable також пропонує foldLeft, foldRight, його передбачати потрібно, щоб перемістити елементи у відомому та фіксованому порядку. Тому можливо реалізувати ітератор для прохідного каналу. Напр. Def iterator = toList.iterator
Traversable
в Scala 2.13 (вона до сих пір зберігається в якості псевдоніма для минаєIterable
до 2.14)