Справочник по Ada 95
4.6 Преобразования типов
Явные преобразования типов, как преобразования значений, так и преобразования представлений, разрешены между тесно связанными типами, как определено ниже. Этот пункт также определяет правила для преобразований значений и представлений к конкретному подтипу типа, как явные, так и неявные в других конструкциях.
Синтаксис
type_conversion ::=
subtype_mark(expression)
| subtype_mark(name)
subtype_mark(expression)
| subtype_mark(name)
Целевой подтип преобразования типа type_conversion — это подтип, обозначенный subtype_mark. Операнд преобразования типа type_conversion — это expression или name в скобках; его тип — тип операнда.
Один тип преобразуем к другому типу, если преобразование типа type_conversion с первым типом как типом операнда и вторым типом как целевым типом является допустимым в соответствии с правилами этого раздела. Два типа преобразуемы, если каждый из них преобразуем к другому.
Преобразование типа type_conversion, операндом которого является name объекта, называется преобразованием представления, если оба его целевой тип и тип операнда являются помеченными, или если оно появляется в качестве фактического параметра с режимом out или in out; другие преобразования типа type_conversion называются преобразованиями значения.
Правила разрешения имен
Ожидается, что операнд преобразования типа type_conversion будет иметь любой тип.
Операнд преобразования представления интерпретируется только как name; операнд преобразования значения интерпретируется как expression.
Правила допустимости
Если целевой тип — числовой тип, то тип операнда должен быть числовым типом.
Если целевой тип — тип массива, то тип операнда должен быть типом массива. Кроме того:
- Типы должны иметь одинаковую размерность;
- Соответствующие типы индексов должны быть преобразуемы;
- Подтипы компонентов должны статически соответствовать; и
- При преобразовании представления целевой тип и тип операнда должны оба или ни один из них иметь ссылочные компоненты.
Если целевой тип — тип общего доступа, то тип операнда должен быть типом доступа к объекту. Кроме того:
- Если целевой тип — тип доступа к переменной, то тип операнда должен быть типом доступа к переменной;
- Если целевой обозначенный тип помечен, то обозначенный тип операнда должен быть преобразуем в целевой обозначенный тип;
- Если целевой обозначенный тип не помечен, то обозначенные типы должны быть одинаковыми, и либо обозначенные подтипы должны статически соответствовать, либо целевой обозначенный подтип должен быть дискриминированным и не ограниченным; и
- Уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности целевого типа. Помимо мест, где обычно применяются правила допустимости (см. 12.3), это правило применяется также в частях с закрытым доступом экземпляра генерируемого блока.
Если целевой тип — тип доступа к подпрограмме, то тип операнда должен быть типом доступа к подпрограмме. Кроме того:
- Определяющие профили должны быть подтиповыми.
- Уровень доступности типа операнда не должен быть статически глубже, чем уровень доступности целевого типа. Помимо мест, где обычно применяются правила допустимости (см. 12.3), это правило применяется также в частях с закрытым доступом экземпляра генерируемого блока. Если тип операнда объявлен внутри тела генерируемого блока, целевой тип должен быть объявлен внутри тела генерируемого блока.
Если целевой тип не входит ни в одну из вышеперечисленных четырёх категорий, должен существовать тип, являющийся предком как целевого типа, так и типа операнда. Кроме того, если целевой тип помечен, то либо:
- Тип операнда должен быть покрыт или происходить от целевого типа; или
- Тип операнда должен быть универсальным типом, который охватывает целевой тип.
При преобразовании представления для непомеченного типа целевой тип должен быть преобразуем (обратно) к типу операнда.
Статическая семантика
Преобразование типа type_conversion, являющееся преобразованием значения, обозначает значение, являющееся результатом преобразования значения операнда в целевой подтип.
Преобразование типа type_conversion, являющееся преобразованием представления, обозначает представление объекта, обозначаемого операндом. Это представление — переменная целевого типа, если операнд обозначает переменную; в противном случае это константа целевого типа.
Номинальный подтип преобразования типа type_conversion — его целевой подтип.
Динамическая семантика
Для вычисления преобразования типа type_conversion, являющегося преобразованием значения, операнд вычисляется, а затем значение операнда преобразуется в соответствующее значение целевого типа, если таковое имеется. Если нет значения целевого типа, соответствующего значению операнда, возникает Constraint_Error; это может произойти только при преобразовании в модулярный тип и только тогда, когда значение операнда находится вне базового диапазона модулярного типа. Следуют дополнительные правила:
- Преобразование числового типа
- Если целевой и тип операнда — оба целочисленные типы, то результат — значение целевого типа, соответствующее тому же математическому целому числу, что и операнд.
- Если целевой тип — десятичный тип с плавающей точкой, то результат усекается (к 0) если значение операнда не является кратным small целевого типа.
- Если целевой тип — какой-либо другой вещественный тип, то результат находится в пределах точности целевого типа (см. G.2, «Требования к производительности чисел'', для реализаций, поддерживающих Приложение по числу).
- Если целевой тип — целочисленный тип, а тип операнда — вещественный, результат округляется до ближайшего целого (в сторону от нуля, если ровно посередине между двумя целыми).
- Преобразование типа перечисления
- Результат — значение целевого типа с тем же порядковым номером, что и значение операнда.
- Преобразование типа массива
- Если целевой подтип — ограниченный подтип массива, то проверяется, что длина каждого измерения значения операнда равна длине соответствующего измерения целевого подтипа. Границы результата — те же, что у целевого подтипа.
- Если целевой подтип — неограниченный подтип массива, то границы результата получаются путём преобразования каждой границы значения операнда в соответствующий тип индекса целевого типа. Для каждого ненулевого диапазона индексов проверяется, что границы диапазона принадлежат соответствующему подтипу индексов.
- В любом случае с массивом, значение каждого компонента результата — это значение соответствующего компонента значения операнда (см. 4.5.2).
- Преобразование составного (не массива) типа
- Значение каждого компонента результата, не являющегося дискриминатором, — это значение соответствующего компонента значения операнда.
- Тег результата — это тег операнда. Если тип операнда — универсальный тип, проверяется, что тег операнда определяет (конкретный) тип, который покрыт или происходит от целевого типа.
- Для каждого дискриминатора целевого типа, соответствующего дискриминатору типа операнда, его значение — это значение соответствующего дискриминатора значения операнда; если он соответствует более чем одному дискриминатору типа операнда, проверяется, что все эти дискриминаторы равны в значении операнда.
- Для каждого дискриминатора целевого типа, соответствующего дискриминатору, заданному в derived_type_definition для какого-либо предка типа операнда (или, если универсальный, какого-либо предка конкретного типа, идентифицируемого тегом операнда), его значение в результате определяется derived_type_definition.
- Для каждого дискриминатора типа операнда, соответствующего дискриминатору, заданному в derived_type_definition для какого-либо предка целевого типа, проверяется, что в значении операнда он равен указанному для него значению.
- Для каждого дискриминатора результата проверяется, что его значение принадлежит его подтипу.
- Преобразование типа доступа
- Для типа доступа к объекту проверяется, что уровень доступности типа операнда не глубже, чем уровень доступности целевого типа.
- Если целевой тип является анонимным типом доступа, выполняется проверка, что значение операнда не равно null; если целевой тип не является анонимным типом доступа, то результат равен null, если значение операнда равно null.
- Если значение операнда не равно null, то результат обозначает тот же объект (или подпрограмму), что и значение операнда, но рассматривается как имеющий целевой обозначенный подтип (или профиль); выполняются любые проверки, связанные с оценкой преобразования в целевой обозначенный подтип.
После преобразования значения в целевой тип, если целевой подтип ограничен, выполняется проверка, удовлетворяет ли значение этому ограничению.
Для оценки преобразования представления операнд имя оценивается, и создается новое представление объекта, обозначаемого операндом, тип которого является целевым типом; если целевой тип составной, выполняются проверки, как описано выше, для преобразования значения.
Свойства этого нового представления следующие:
- Если целевой тип составной, границы или дискриминанты (если таковые имеются) представления определяются, как описано выше для преобразования значения; каждый компонент представления, не являющийся дискриминантом, обозначает соответствующий компонент объекта операнда; подтип представления ограничен, если либо целевой подтип, либо объект операнда ограничен, или если целевой подтип неопределен, или если тип операнда является потомком целевого типа и имеет дискриминанты, которые не были унаследованы от целевого типа;
- Если целевой тип помечен, то присваивание представлению присваивает соответствующую часть объекта, обозначаемого операндом; в противном случае присваивание представлению присваивает объекту, после преобразования присвоенного значения в подтип объекта (что может вызвать Constraint_Error);
- Чтение значения представления дает результат преобразования значения объекта операнда в целевой подтип (что может вызвать Constraint_Error), за исключением случая, когда объект является типом доступа и преобразование представления передается в качестве параметра out; в последнем случае значение объекта операнда используется для инициализации формального параметра без проверки на соответствие какому-либо ограничению целевого подтипа (см. 6.4.1).
Если проверка доступа Accessibility_Check завершается неудачно, возбуждается Program_Error. Любая другая проверка, связанная с преобразованием, возбуждает Constraint_Error в случае неудачи.
Преобразование в тип эквивалентно преобразованию в неограниченный подтип типа.
ПРИМЕЧАНИЯ
20 Помимо явных преобразований type_conversion, преобразования типов выполняются неявно в ситуациях, когда ожидаемый тип и фактический тип конструкта различаются, как это разрешено правилами разрешения типов (см. 8.6). Например, целочисленная литерал имеет тип universal_integer и неявно преобразуется при присваивании целевому типу конкретного целочисленного типа. Аналогично, фактический параметр конкретного помеченного типа неявно преобразуется, когда соответствующий формальный параметр является типом класса.
21 Даже когда ожидаемые и фактические типы совпадают, неявные преобразования подтипов выполняются для корректировки границ массива (если таковые имеются) операнда для соответствия желаемому целевому подтипу или для возбуждения Constraint_Error, если (возможно, скорректированное) значение не удовлетворяет ограничениям целевого подтипа.
Следствием правил разрешения перегрузки является то, что операнд явного type_conversion не может быть литералом null, аллокатором, агрегатом, строковой_литералью, символьной_литералью или ссылкой attribute_reference на атрибут доступа или Unchecked_Access. Аналогично, такая выражение, заключенная в скобки, не допускается. qualified_expression (см. 4.7) может использоваться вместо такого type_conversion.
22 Ограничение целевого подтипа не оказывает влияния на type_conversion элементарного типа, переданного в качестве параметра 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