Курс языка программирования Raku / Функциональное, конкурентное, реактивное и веб-программирование / Функциональное программирование / Итераторы
Протокол итератора
Всякое значение, по которому можно пройти циклом — список, диапазон,
массив, — может выдать вам итератор методом
.iterator. У итератора есть один главный метод,
pull-one, который при каждом вызове возвращает следующее
значение:
my $it = (10, 20, 30).iterator;
say $it.pull-one; # 10
say $it.pull-one; # 20
say $it.pull-one; # 30Когда значения заканчиваются, pull-one возвращает не
настоящий элемент, а особый маркер — IterationEnd. Запрос
ещё одного значения у того же $it это и показывает:
say $it.pull-one =:= IterationEnd; # TrueОператор =:= проверяет, что это тот же самый
объект, — именно так маркер и распознают. Эта деталь важна
внутри цикла, где нужно и сохранить вытянутое значение, и проверить его.
Если присвоить его через =, значение
попадёт в контейнер, и сравнение станет смотреть на контейнер, а не на
IterationEnd. Средство от этого — связать
через :=, чтобы переменная попросту и была тем,
что вернул pull-one:
my $it = <a b c>.iterator;
loop {
my $v := $it.pull-one; # связываем, а не присваиваем
last if $v =:= IterationEnd;
say $v;
}Цикл печатает a, b, c, а затем
останавливается. Ровно это цикл for и делает за вас под
капотом: он вызывает .iterator у того, по чему вы идёте, и
продолжает вызывать pull-one, пока не встретит
IterationEnd. Писать это вручную приходится редко, но,
сделав так однажды, видишь: Raku на самом деле проходит циклом по
итераторам, а не по спискам.
Практика
Пройдите 1 тест по содержанию этой темы.
Навигация по курсу
← Итераторы | Тест — Протокол итератора →
💪 Или перейдите сразу к упражнению
этого раздела.