Решение, опубликованное OP, является допустимым, но в D2 есть другое решение с другим набором компромиссов. Итерацию в D можно разделить на внутреннюю итерацию, которая обрабатывается opApply, и внешнюю итерацию, которая обрабатывается диапазонами.
Внутренняя итерация дает итерируемому объекту контроль над стеком вызовов. Это позволяет, например, использовать рекурсию для объекта, итерируемого без сохранения явного стека, но делает невозможным итерацию по нескольким структурам в шаге блокировки. Внешняя итерация делает обратное.
Внешняя итерация осуществляется через диапазоны. Диапазон - это любой класс или структура, которые определяют три метода: front()
предоставляет доступ к первому элементу в диапазоне, popFront()
увеличивает диапазон и empty()
возвращает true
, если диапазон пуст. Если диапазон бесконечен, пустой может быть объявлен как константа вместо функции-члена. Таким образом, вызывающая сторона контролирует стек вызовов, который может быть хорошим или плохим в зависимости от ситуации.
Вот пример использования диапазонов для итерации:
/**This struct lazily produces all Fibonacci numbers.*/
struct Fibonacci {
ulong num1 = 0;
ulong num2 = 1;
ulong front() {
return num1 + num2;
}
void popFront() {
auto newNum2 = num1 + num2;
num1 = num2;
num2 = newNum2;
}
// A range of Fibonacci numbers is infinite.
enum bool empty = false;
}