Menu

Дiапазони

Коли компiлятор зустрічає вираз foreach

foreach (element; range)
{
    // Тіло циклу...
}

вiн на нижчому рівні перепиcує його в:

for (auto __rangeCopy = range;
     !__rangeCopy.empty;
     __rangeCopy.popFront())
 {
    auto element = __rangeCopy.front;
    // Тіло циклу...
}

Якщо об'єкт діапазону є посиланням (class), то діапазон можна використовувати, але при цьому він не буде доступний для подальшої ітерації (тільки якщо головний цикл завершиться чи перерветься до потрібного циклу). Якщо об'єкт діапазону є простий тип (int, struct...), буде зроблена копія діапазону і залежно від пособу визначення діапазону у циклі або може або не може використовуватись оригінальний діапазон. Більшість діапазонів у стандартній бібліотеці є структурами, а отже ітерація за допомогою foreach зазвичай неруйнівна, хоча це не гарантовано. Якщо гарантія важлива, потрібно використовувати forward діапазони.

Будь-який об'єкт, який імплементує наступний інтерфейс, називається діапазон і може пiдтримувати ітерації:

    struct Range
    {
        @property bool empty() const;
        void popFront();
        T front() const;
    }

Зверніть увагу, що хоч функції empty та front і позначені як const (мається на увазі, що виклик їх не змінить Range), так робити не обов'язково.

Функції у std.range і std.algorithm забезпечують будівельні блоки, які використовують цей інтерфейс. Діапазони дозволяють створювати складні алгоритми обробки об'єктiв, по яким може бути проведена ітерація. Крім того, діапазони дозволяють створювати ледачi об'єкти, які виконують обчислення тільки, коли це дійсно необхідно, наприклад, коли наступний елемент діапазону є реально доступним. Спецiальнi алгоритми для діапазонiв будуть описані пізніше у розділі Коштовності D.

Вправа

Завершіть код та створіть дiапазон FibonacciRange, який повертає числа Фібоначчі. Не вводьте себе в оману, видаляючи assert-и!

Додатково

rdmd playground.d