Справочник Ada 2012
5.5.2 Обобщенная итерация цикла
Обобщенные формы итерации цикла обеспечиваются спецификацией_итератора.
Синтаксис
спецификация_итератора ::=
идентификатор_определения в [обратном] итератор_имя
| идентификатор_определения [: указание_подтипа] из [обратном] итерируемое_имя
идентификатор_определения в [обратном] итератор_имя
| идентификатор_определения [: указание_подтипа] из [обратном] итерируемое_имя
Правила разрешения имен
Для первой формы спецификации_итератора, называемой обобщенным итератором, ожидаемый тип для итератор_имя — любой тип итератора. Для второй формы спецификации_итератора ожидаемый тип для итерируемое_имя — любой тип массива или итерируемого контейнера. Если итерируемое_имя обозначает массив объектов, то спецификация_итератора называется итератором по компонентам массива; в противном случае — итератором по элементам контейнера.
Правила легальности
Если зарезервированное слово обратном встречается, спецификация_итератора является обратным итератором; в противном случае — прямым итератором. В обратном обобщенном итераторе итератор_имя должен быть типа обратимого итератора. В обратном итераторе по элементам контейнера, тип по умолчанию для типа итерируемое_имя должен быть типом обратимого итератора.
Подтип, определенный указание_подтипа, если он есть, в итераторе по компонентам массива, должен статически соответствовать подтипу компонента типа итерируемое_имя. Подтип, определенный указание_подтипа, если он есть, в итераторе по элементам контейнера должен статически соответствовать подтипу элемента по умолчанию для типа итерируемое_имя.
В итераторе по элементам контейнера, где итерируемое_имя имеет тип T, если итерируемое_имя обозначает константу или аспект Variable_Indexing не указан для T, тогда аспект Constant_Indexing должен быть указан для T.
Итератор_имя или итерируемое_имя в спецификации_итератора не должны обозначать подкомпоненты, зависящие от дискриминантов объекта, номинальный подтип которого не ограничен, если объект не известен как ограниченный.
Итератор по элементам контейнера не является легальным, если вызов функции итератора по умолчанию, который создает итератор цикла (см. ниже), не является легальным.
Обобщенный итератор не является легальным, если подтип курсора итерации итератор_имя является ограниченным типом в момент обобщенного итератора. Итератор по элементам контейнера не является легальным, если подтип курсора по умолчанию типа итерируемое_имя является ограниченным типом в момент итератора по элементам контейнера.
Статическая семантика
Спецификация_итератора объявляет параметр_цикла. В обобщенном итераторе номинальный подтип параметра цикла — подтип курсора итерации. В итераторе по компонентам массива или итераторе по элементам контейнера, если указание подтипа присутствует, оно определяет номинальный подтип параметра цикла. В итераторе по компонентам массива, если указание подтипа отсутствует, номинальный подтип параметра цикла — подтип компонента типа итерируемое_имя. В итераторе по элементам контейнера, если указание подтипа отсутствует, номинальный подтип параметра цикла — подтип элемента по умолчанию для типа итерируемое_имя.
В обобщенном итераторе параметр цикла является константой. В итераторе по компонентам массива параметр цикла является константой, если итерируемое_имя обозначает константу; в противном случае — переменную. В итераторе по элементам контейнера, параметр цикла является константой, если итерируемое_имя обозначает константу или если аспект Variable_Indexing не указан для типа итерируемое_имя; в противном случае — переменная.
Динамическая семантика
Для выполнения оператора цикла с оператор_цикла и спецификацией_итератора, сначала обрабатывается спецификация_итератора. Эта обработка обрабатывает указание_подтипа, если таковое имеется.
Для обобщенного итератора параметр цикла создается, итератор_имя вычисляется, и обозначенный объект итератора становится итератором_цикла. В прямом обобщенном итераторе операция First типа итератора вызывается для итератора цикла, чтобы получить начальное значение для параметра цикла. Если результат вызова Has_Element для начального значения равен False, то выполнение оператора цикла завершается. В противном случае последовательность операторов выполняется, а затем операция Next типа итератора вызывается с итератором цикла и текущим значением параметра цикла, чтобы получить следующее значение для присваивания параметру цикла. Это повторяется до тех пор, пока результат вызова Has_Element для параметра цикла не станет False или цикл не будет прерван в результате изменения управления. Для обратного обобщенного итератора операции Last и Previous вызываются вместо First и Next.
Для итератора по компонентам массива итерируемое_имя вычисляется, и обозначенный объект массива становится массивом_для_цикла. Если массив для цикла — нулевой массив, то выполнение оператора цикла завершается. В противном случае, операторы последовательности выполняются с параметром цикла, обозначающим каждый компонент массива для цикла, используя канонический порядок компонентов, где последняя размерность изменяется быстрее (если у массива нет соглашения Fortran, в этом случае первой изменяется первая размерность). Для прямого итератора по компонентам массива итерация начинается с компонента, индекс которого имеет наименьшие значения, и продолжается в каноническом порядке. Для обратного итератора по компонентам массива итерация начинается с компонента, индекс которого имеет наибольшие значения, и продолжается в обратном каноническом порядке. Итерация цикла продолжается до тех пор, пока операторы последовательности не будут выполнены для каждого компонента массива для цикла или пока цикл не будет прерван в результате изменения управления.
Для итератора по элементам контейнера итерируемое_имя вычисляется, и обозначенный объект итерируемого контейнера становится объектом_контейнера_для_цикла. Функция итератора по умолчанию для типа объекта итерируемого контейнера для цикла вызывается с объектом итерируемого контейнера, и результат является итератором_цикла. Создается объект подтипа курсора по умолчанию (курсор_цикла).
Для итератора элементов контейнера вперед операция First типа итератора вызывается для итератора цикла, чтобы получить начальное значение для курсора цикла. Если результат вызова Has_Element для начального значения равен False, то выполнение операции_цикла завершено. В противном случае, последовательность_операций выполняется с параметром цикла, обозначающим индексирование (см. 4.1.6) в объекте итерируемого контейнера для цикла, при этом единственным параметром индексирования является текущее значение курсора цикла; затем операция Next типа итератора вызывается с итератором цикла и курсором цикла, чтобы получить следующее значение, которое должно быть присвоено курсору цикла. Это повторяется до тех пор, пока результат вызова Has_Element для курсора цикла не будет False или пока цикл не будет прерван в результате передачи управления. Для итератора элементов контейнера назад вызываются операции Last и Previous вместо First и Next. Если параметр цикла является константой (см. выше), то индексирование использует функцию индексирования по умолчанию для типа объекта итерируемого контейнера для цикла; в противном случае используется функция индексирования по умолчанию для переменной.
Любое исключение, распространяемое в результате выполнения обобщенного итератора или итератора элементов контейнера, распространяется ближайшим окружающим оператором цикла.
Примеры
-- Пример итератора компонентов массива:
for Элемент of Board loop -- См. 3.6.1.
Element := Element * 2.0; -- Удваивает каждый элемент Board, двумерного массива.
end loop;
for Элемент of Board loop -- См. 3.6.1.
Element := Element * 2.0; -- Удваивает каждый элемент Board, двумерного массива.
end loop;
Примеры использования обобщенных итераторов см. в A.18.32 и соответствующих пакетах контейнеров в A.18.2 и A.18.3.