Справочник Ada 2012
4.6 Преобразования типов
Явные преобразования типов, как преобразования значений, так и преобразования представлений, разрешены между тесно связанными типами, как определено ниже. Этот подраздел также определяет правила для преобразований значений и представлений к определенному подтипу типа, как явные, так и неявные в других конструкциях.
Синтаксис
Целевой подтип type_conversion — это подтип, обозначаемый subtype_mark. Операнд type_conversion — это expression или name в скобках; его тип — тип операнда.
Один тип преобразуем ко второму типу, если type_conversion с первым типом как типом операнда и вторым типом как целевым типом является допустимым в соответствии с правилами этого подраздела. Два типа преобразуемы, если каждый преобразуем к другому.
type_conversion, операндом которого является имя объекта, называется преобразованием представления, если его целевой тип и тип операнда являются помеченными, или если оно появляется в вызове в качестве фактического параметра с режимом out или in out; другие type_conversion называются преобразованиями значений.
Правила разрешения имен
Операнд type_conversion ожидается любого типа.
Операнд преобразования представления интерпретируется только как имя; операнд преобразования значения интерпретируется как выражение.
Правила допустимости
При преобразовании представления для непомеченного типа целевой тип должен быть преобразуем (обратно) к типу операнда.
Абзацы с 9 по 20 были перегруппированы и перемещены ниже.
Если существует тип (кроме корневого числового типа), который является предком как целевого типа, так и типа операнда, или оба типа являются типами-классами, тогда должно выполняться хотя бы одно из следующих правил:
- Целевой тип должен быть непомеченным; или
- Тип операнда должен быть покрыт или происходить из целевого типа; или
- Тип операнда должен быть типом-классом, который охватывает целевой тип; или
- Тип операнда и целевой тип должны быть типами-классами, и конкретный тип, связанный хотя бы с одним из них, должен быть типом интерфейса.
Если нет типа (кроме корневого числового типа), который является предком как целевого типа, так и типа операнда, и они не оба типы-классы, то должно выполняться одно из следующих правил:
- Если целевой тип является числовым типом, то тип операнда должен быть числовым типом.
- Если целевой тип является типом массива, то тип операнда должен быть типом массива. Кроме того:
Типы должны иметь одинаковую размерность;
Соответствующие типы индексов должны быть преобразуемы;
Подтипы компонентов должны статически совпадать;
Если типы компонентов — анонимные типы доступа, то уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности целевого типа;
Ни целевой тип, ни тип операнда не должны быть ограниченными;
Если целевой тип преобразования представления имеет алиасовые компоненты, то тип операнда также должен иметь;
Тип операнда преобразования представления не должен иметь помеченный, приватный или изменчивый подкомпонент.
- Если целевой тип — universal_access, то тип операнда должен быть типом доступа.
- Если целевой тип — общий тип доступа к объекту, то тип операнда должен быть universal_access или типом доступа к объекту. Кроме того, если тип операнда не universal_access:
Если целевой тип — тип доступа к переменной, то тип операнда должен быть типом доступа к переменной;
Если целевой тип объекта является помеченным, то тип объекта операнда должен быть преобразуем в целевой тип объекта;
Если целевой тип объекта не помеченный, то назначенные типы должны быть одинаковыми, и либо:
назначенные подтипы должны статически совпадать; или
назначенный тип должен быть дискриминирован в полном представлении и не ограничен ни в каком частичном представлении, и один из назначенных подтипов должен быть не ограничен;
Уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности целевого типа, за исключением случая, когда целевой тип является анонимным типом доступа к автономному объекту. Если целевой тип — такой автономный объект, уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности объявления автономного объекта.
- Если целевой тип — тип доступа к объекту, специфичный для пула, то тип операнда должен быть universal_access.
- Если целевой тип — тип доступа к подпрограмме, то тип операнда должен быть universal_access или типом доступа к подпрограмме. Кроме того, если тип операнда не universal_access:
Определяющие профили должны соответствовать подтипам.
Уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности целевого типа. Если тип операнда объявлен в теле обобщенного блока, целевой тип должен быть объявлен в теле обобщенного блока.
В дополнение к местам, где обычно применяются правила допустимости (см. 12.3), эти правила применяются также в приватной части экземпляра обобщенного блока.
Статическая семантика
Преобразование типа type_conversion, являющееся преобразованием значения, обозначает значение, являющееся результатом преобразования значения операнда в целевой подтип.
Преобразование типа type_conversion, являющееся преобразованием представления, обозначает представление объекта, обозначаемого операндом. Это представление — переменная целевого типа, если операнд обозначает переменную; в противном случае — константа целевого типа.
Номинальный подтип type_conversion — это его целевой подтип.
Динамическая семантика
Для оценки преобразования типа type_conversion, являющегося преобразованием значения, операнд оценивается, а затем значение операнда преобразуется в соответствующее значение целевого типа, если таковое существует. Если нет значения целевого типа, соответствующего значению операнда, поднимается Constraint_Error; это может произойти только при преобразовании в модулярный тип и только тогда, когда значение операнда находится вне базового диапазона модулярного типа. Следуют дополнительные правила:
- Преобразование числового типа
Если целевой и тип операнда являются целыми типами, то результатом является значение целевого типа, соответствующее тому же математическому целому числу, что и операнд.
Если целевой тип — тип десятичной фиксированной точки, то результат усекается (к 0), если значение операнда не является кратным small целевого типа.
Если целевой тип — какой-либо другой вещественный тип, то результат находится в пределах точности целевого типа (см. G.2, «Требования к производительности чисел», для реализаций, поддерживающих Приложение к Числам).
Если целевой тип — целого типа, а тип операнда — вещественный, то результатом является округленное до ближайшего целого (от нуля, если ровно посередине между двумя целыми числами).
- Преобразование типа перечисления
Результат — это значение целевого типа с тем же номером позиции, что и значение операнда.
- Преобразование типа массива
Если целевой подтип — ограниченный подтип массива, то проверяется, что длина каждой размерности значения операнда равна длине соответствующей размерности целевого подтипа. Границы результата — это границы целевого подтипа.
Если целевой подтип — неограниченный подтип массива, то границы результата получаются путем преобразования каждой границы значения операнда в соответствующий тип индекса целевого типа. Для каждого ненулевого диапазона индексов проверяется, что границы диапазона принадлежат соответствующему подтипу индекса.
В обоих случаях массивов, значение каждого компонента результата — это значение соответствующего компонента значения операнда (см. 4.5.2).
Если типы компонентов типов массивов — анонимные типы доступа, то проверяется, что уровень доступности типа операнда не глубже, чем уровень доступности целевого типа.
- Преобразование составного (не массива) типа
Значение каждого недискриминационного компонента результата равно соответствующему компоненту значения операнда.
Метка результата — это метка операнда. Если тип операнда — широко распространенный класс, проверяется, что метка операнда идентифицирует (конкретный) тип, который охватывается или происходит от целевого типа.
Для каждого дискриминанта целевого типа, соответствующего дискриминанту типа операнда, его значение равно значению соответствующего дискриминанта значения операнда; если он соответствует более чем одному дискриминанту типа операнда, проверяется, что все эти дискриминанты равны в значении операнда.
Для каждого дискриминанта целевого типа, соответствующего дискриминанту, указанному в определении_типа_производного для какого-либо предка типа операнда (или, если широко распространенный класс, для какого-либо предка конкретного типа, идентифицированного меткой операнда), его значение в результате определяется значением, указанным в определении_типа_производного.
Для каждого дискриминанта типа операнда, соответствующего дискриминанту, указанному в определении_типа_производного для какого-либо предка целевого типа, проверяется, что в значении операнда он равен значению, указанному для него.
Для каждого дискриминанта результата проверяется, что его значение принадлежит его подтипу.
- Преобразование типов доступа
Для типа доступа к объекту проверяется, что уровень доступности типа операнда не глубже, чем уровень целевого типа, если только целевой тип не является анонимным типом доступа к автономному объекту. Если целевой тип является типом такого автономного объекта, проверяется, что уровень доступности типа операнда не глубже, чем уровень объявления автономного объекта; затем, если проверка пройдена, уровень доступности целевого типа становится равным уровню доступности типа операнда.
Если значение операнда равно null, результат преобразования — значение null целевого типа.
Если значение операнда не равно null, то результат обозначает тот же объект (или подпрограмму), что и значение операнда, но рассматривается как принадлежащий целевому обозначенному подтипу (или профилю); выполняются все проверки, связанные с оценкой преобразования в целевой обозначенный подтип.
После преобразования значения в целевой тип, если целевой подтип ограничен, выполняется проверка, удовлетворяет ли значение этому ограничению. Если целевой подтип исключает null, то проверяется, что значение не равно null. Если для целевого подтипа включены проверки предиката (см. 3.2.4), выполняется проверка, удовлетворяет ли значение предикатам целевого подтипа.
Для оценки преобразования представления операнд имя оценивается, и создаётся новое представление объекта, обозначаемого операндом, тип которого — целевой тип; если целевой тип составной, выполняется проверка, как описано выше, для преобразования значения.
Свойства этого нового представления следующие:
- Если целевой тип составной, границы или дискриминанты (если есть) представления определяются, как описано выше, для преобразования значения; каждый недискриминационный компонент представления обозначает соответствующий компонент объекта операнда; подтип представления ограничен, если либо целевой подтип, либо объект операнда ограничен, либо целевой подтип неопределён, или если тип операнда является потомком целевого типа и имеет дискриминанты, которые не были унаследованы от целевого типа;
- Если целевой тип помеченный, то присваивание представлению присваивает соответствующую часть объекта, обозначаемого операндом; в противном случае присваивание представлению присваивает объект после преобразования присвоенного значения в подтип объекта (что может вызвать Constraint_Error);
- Чтение значения представления приводит к результату преобразования значения объекта операнда в целевой подтип (что может вызвать Constraint_Error), за исключением случаев, когда объект имеет элементарный тип, и преобразование представления передаётся в качестве параметра out; в последнем случае значение объекта операнда может быть использовано для инициализации формального параметра без проверки на соответствие какому-либо ограничению целевого подтипа (как более точно описано в 6.4.1).
Если проверка доступа терпит неудачу, поднимается Program_Error. Если проверка предиката терпит неудачу, то эффект определяется в подразделе 3.2.4, «Предикаты подтипов». Любая другая проверка, связанная с преобразованием, вызывает Constraint_Error при неудаче.
Преобразование в тип эквивалентно преобразованию в неограниченный подтип типа.
Оценка преобразования значения составного типа либо создаёт новый анонимный объект (аналогично объекту, созданному при оценке агрегата или вызова функции) или возвращает новое представление объекта операнда без создания нового объекта:
- Если целевой тип — тип по ссылке, и существует тип, являющийся предком как целевого типа, так и типа операнда, то новый объект не создаётся;
- Если целевой тип — тип массива с алиасами компонентов, а тип операнда — тип массива с неалиасированными компонентами, то создаётся новый объект;
- В противном случае, неявно, создаётся новый объект или нет.
Если создаётся новый объект, то инициализация этого объекта является операцией присваивания.
ПРИМЕЧАНИЯ
20 Помимо явных преобразований_типов, преобразования типов выполняются неявно в ситуациях, когда ожидаемый тип и фактический тип конструкции различаются, как это разрешено правилами разрешения типов (см. 8.6). Например, целочисленная литерал имеет тип universal_integer и неявно преобразуется при присваивании целевому типу какого-либо конкретного целочисленного типа. Аналогично, фактический параметр конкретного помеченного типа неявно преобразуется, когда соответствующий формальный параметр имеет тип широко распространённого класса.
Даже если ожидаемые и фактические типы совпадают, выполняются неявные преобразования подтипов для корректировки границ массива (если есть) операнда, чтобы соответствовать целевому подтипу, или для поднятия Constraint_Error, если (возможно, скорректированное) значение не удовлетворяет ограничениям целевого подтипа.
21 Следствием правил разрешения перегрузки является то, что операндом (явного) преобразования_типов не может быть аллокатор, агрегат, строковая_литерал, символьная_литерал или ссылка_на_атрибут для атрибутов Access или Unchecked_Access. Аналогично, такая выражение, заключённая в скобки, запрещена. Вместо такого преобразования_типов можно использовать квалифицированное_выражение (см. 4.7).
22 Ограничение целевого подтипа не оказывает влияния на преобразование_типов элементарного типа, переданного в качестве параметра out. Поэтому рекомендуется указывать первый подтип в качестве целевого, чтобы минимизировать путаницу (аналогичная рекомендация относится к переименованию и формальным объектам in out обобщённых типов).
Примеры
Примеры преобразования числовых типов:
Real(2*J) -- значение преобразуется в число с плавающей точкой
Integer(1.6) -- значение равно 2
Integer(-0.4) -- значение равно 0
Integer(1.6) -- значение равно 2
Integer(-0.4) -- значение равно 0
Пример преобразования между производными типами:
type A_Form is new B_Form;
X : A_Form;
Y : B_Form;
Y : B_Form;
X := A_Form(Y);
Y := B_Form(X); -- обратное преобразование
Y := B_Form(X); -- обратное преобразование
Примеры преобразований между типами массивов:
type Sequence is array (Integer range <>) of Integer;
subtype Dozen is Sequence(1 .. 12);
Ledger : array(1 .. 100) of Integer;
subtype Dozen is Sequence(1 .. 12);
Ledger : array(1 .. 100) of Integer;
Sequence(Ledger) -- границы — это границы Ledger
Sequence(Ledger(31 .. 42)) -- границы — 31 и 42
Dozen(Ledger(31 .. 42)) -- границы — это границы Dozen
Sequence(Ledger(31 .. 42)) -- границы — 31 и 42
Dozen(Ledger(31 .. 42)) -- границы — это границы Dozen