Курс Raku / Функційне, конкурентне, реактивне та веб-програмування / Функційне програмування / Ітератори

Написання ітератора

Ітератор — це просто об’єкт, що виконує вбудовану роль Iterator і надає метод pull-one. Цей метод повертає наступне значення або IterationEnd, коли нічого не залишилося. Ось ітератор зворотного відліку, що видає число й крокує до нуля:

class Countdown does Iterator {
    has Int $.n is rw;

    method pull-one {
        return IterationEnd if $!n <= 0;
        return $!n--;
    }
}

Кожен виклик pull-one спершу перевіряє, чи не вичерпався лічильник; якщо ні, повертає поточне число й зменшує його. Постфіксний декремент $!n-- повертає значення до віднімання, тож числа виходять як 3, 2, 1. Керування ним вручну має такий самий вигляд, як і з будь-яким іншим ітератором:

my $c = Countdown.new(n => 3);
say $c.pull-one; # 3
say $c.pull-one; # 2
say $c.pull-one; # 1
say $c.pull-one =:= IterationEnd; # True

Сам собою ітератор не є тим, що цикл for може взяти напряму, — цикл очікує ітерабельне. Загорніть ітератор у Seq, і він стане придатним для циклу:

for Seq.new(Countdown.new(n => 3)) -> $x {
    say $x;
}

Це друкує 3, 2, 1. У повсякденному коді ви взяли б натомість gather / take — форма генератора значно коротша для того самого результату. Проте написати роль Iterator напряму варто хоча б раз побачити, бо це оголює те, на чому збудовані gather, map і кожен цикл for: об’єкт, що відповідає на одне-єдине запитання — «яке наступне значення?»

Навігація курсом

Тест — Протокол ітератора   |   Сума за допомогою pull-one


💪 Або перейдіть одразу до вправи цього розділу.