Курс по 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


💪 Или преминете направо към упражнението към този раздел.