Коли комп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
-и!