Справочник по Ada (Ada 2022)
4.5.2 Операторы сравнения и проверки принадлежности
Операторы равенства = (равно) и /= (не равно) определены для нелимитированных типов. Другие операторы relational_operator являются операторами упорядочения < (меньше), <= (меньше или равно), > (больше) и >= (больше или равно). Операторы упорядочения определены для скалярных типов и для дискретных типов массивов, то есть одномерных массивов, компоненты которых имеют дискретный тип.
Проверка принадлежности, используя in или not in, определяет, принадлежит ли значение заданному подтипу или диапазону, равно ли оно заданному значению, имеет ли оно метку, идентифицирующую тип, покрываемый данным типом, или может ли быть преобразовано и имеет ли соответствующий уровень доступа для данного типа доступа. Проверки принадлежности разрешены для всех типов.
Правила разрешения имен
Проверяемый тип проверки принадлежности определяется с помощью membership_choice из membership_choice_list. Или все membership_choice в membership_choice_list должны разрешаться в один и тот же тип, который является проверяемым типом; или каждый membership_choice должен быть элементарного типа, а проверяемый тип должен быть покрыт каждым из этих элементарных типов.
Если проверяемый тип помечен, то simple_expression должен разрешиться в тип, который может быть преобразован (см. 4.6) в проверяемый тип; если непомечен, ожидаемый тип simple_expression — это проверяемый тип. Ожидаемый тип simple_expression в membership_choice и simple_expression диапазона в membership_choice — это проверяемый тип операции проверки принадлежности.
Правила легальности
Для проверки принадлежности, если simple_expression имеет тип класса-широкого типа, то проверяемый тип должен быть (видимо) помечен.
Если проверка принадлежности содержит один или несколько simple_expressions и проверяемый тип проверки принадлежности ограничен, то проверяемый тип проверки принадлежности должен иметь видимый примитивный оператор равенства; если проверяемый тип проверки принадлежности нелимитирован с определенным пользователем примитивным оператором равенства, определённым в момент, когда тип лимитирован, проверяемый тип должен быть типом записи или расширением записи.
Статическая семантика
Тип результата проверки принадлежности — это предопределенный тип Boolean.
Операторы равенства предопределены для каждого конкретного типа T, который не является ограниченным и не является анонимным типом доступа, со следующими спецификациями:
function "=" (Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
Следующие дополнительные операторы равенства для типа universal_access объявлены в пакете Standard для использования с анонимными типами доступа:
function "=" (Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
Операторы упорядочения предопределены для каждого конкретного скалярного типа T и для каждого дискретного типа массивов T со следующими спецификациями:
function "<" (Left, Right : T) return Boolean
function "<="(Left, Right : T) return Boolean
function ">" (Left, Right : T) return Boolean
function ">="(Left, Right : T) return Boolean
function "<="(Left, Right : T) return Boolean
function ">" (Left, Right : T) return Boolean
function ">="(Left, Right : T) return Boolean
Правила разрешения имен
По крайней мере один из операндов оператора равенства для universal_access должен быть конкретного анонимного типа доступа. Если предопределенный оператор равенства не определен с использованием расширенного имени с prefix, обозначающим пакет Standard, ни один из операндов не должен быть типа доступа к объекту, назначенный тип которого D или D'Class, где D имеет определенный пользователем примитивный оператор равенства, такой что:
- его тип результата — Boolean;
- он объявлен непосредственно в том же списке объявления, что и D или любое частичное или неполное представление D; и
- по крайней мере один из его операндов — это параметр доступа с назначенным типом D.
Правила легальности
По крайней мере один из операндов операторов равенства для universal_access должен иметь тип universal_access, или оба должны быть типов доступа к объектам, или оба должны быть типов доступа к подпрограммам. Кроме того:
- Когда оба имеют тип доступа к объектам, назначенные типы должны быть одинаковыми или один должен покрывать другой, и если назначенные типы являются элементарными или массивами, то назначенные подтипы должны статически соответствовать;
- Когда оба имеют тип доступа к подпрограммам, назначенные профили должны соответствовать подтипу.
Если профиль явно объявленного примитивного оператора равенства для типа записи без метки соответствует профилю соответствующего предопределенного оператора равенства, объявление должно произойти до того, как тип станет замороженным. Кроме того, ни один тип не должен быть получен из типа записи без метки до объявления примитивного оператора равенства. В дополнение к местам, где обычно применяются Правила легальности (см. 12.3), это правило применяется также в частях с private для экземпляров генерируемого блока.
Динамическая семантика
Для дискретных типов предопределенные операторы сравнения определены через соответствующие математические операции над номерами позиций значений операндов.
Для вещественных типов предопределенные операторы сравнения определены в терминах соответствующих математических операций над значениями операндов с учетом точности типа.
Два значения доступа к объектам равны, если они обозначают один и тот же объект, или если оба равны нулевому значению типа доступа.
Два значения доступа к подпрограммам равны, если они являются результатом одного и того же вычисления атрибута доступа attribute_reference, или если оба равны нулевому значению типа доступа. Два значения доступа к подпрограммам не равны, если они обозначают разные подпрограммы. Не определено, равны или не равны два значения доступа, которые обозначают одну и ту же подпрограмму, но являются результатом различных вычислений attribute_reference.
Для расширения типа предопределенное равенство определяется в терминах примитивного (возможно, определенного пользователем) оператора equals для родительского типа и для любых компонентов, имеющих тип записи в части расширения, и предопределённое равенство для любых других компонентов, не унаследованных от родительского типа.
Для частного типа, если его полный тип — тип записи или расширение записи, предопределенное равенство определяется через примитивный оператор equals полного типа; в противном случае предопределённое равенство для частного типа — это равенство его полного типа.
Для других составных типов предопределённые операторы равенства (и некоторые другие предопределённые операции над составными типами — см. 4.5.1 и 4.6) определены через соответствующую операцию над соответствующими компонентами, определёнными следующим образом:
- Для двух составных объектов или значений одного и того же типа, не являющегося массивом, соответствующими компонентами являются те, которые соответствуют одному и тому же component_declaration или discriminant_specification;
- Для двух одномерных массивов одного и того же типа соответствующие компоненты — это (если таковые есть) те, значения индексов которых совпадают в следующем смысле: нижние границы диапазонов индексов определены как совпадающие, и преемники соответствующих индексов определены как совпадающие;
- Для двух многомерных массивов одного и того же типа соответствующие компоненты — это те, значения индексов которых совпадают в последовательных позициях индексов.
Аналогичные определения применяются, если типы двух объектов или значений преобразуемы, а не одинаковы.
Исходя из приведенного выше определения соответствующих компонентов, результат предопределенного оператора equals для составных типов (кроме тех составных типов, которые рассматривались ранее) определяется следующим образом:
- Если компонентов нет, то результат определён как True;
- Если есть несоответствующие компоненты, то результат определён как False;
- В противном случае результат определяется через примитивный оператор equals для любых соответствующих компонентов, являющихся записями, и предопределённое равенство для любых других соответствующих компонентов.
Если оператор равенства для примитивного типа записи без тегов является абстрактным, то Program_Error поднимается в момент любого вызова этого абстрактного подпрограммы, неявно как часть операции сравнения на включённом составном объекте или в экземпляре обобщенного с формальным закрытым типом, где фактический тип является типом записи с абстрактным «=».
Для любого составного типа порядок, в котором вызывается «=» для компонентов, не определён. Кроме того, если результат может быть определён до вызова «=» для некоторых компонентов, не определено, будет ли «=» вызван для этих компонентов.
Предопределённый оператор «/=” возвращает результат, обратный предопределённому оператору «=».
Для дискретного типа массива предопределённые операторы упорядочения соответствуют *лексикографическому порядку* с использованием предопределённого отношения порядка типа компонента: Нулевой массив лексикографически меньше любого массива, имеющего по крайней мере один компонент. В случае ненулевых массивов левый операнд лексикографически меньше правого операнда, если первый компонент левого операнда меньше, чем у правого; в противном случае левый операнд лексикографически меньше правого операнда только в том случае, если их первые компоненты равны, и хвост левого операнда лексикографически меньше, чем у правого (хвост состоит из оставшихся компонентов, кроме первого, и может быть нулевым).
*Тест принадлежности отдельного элемента* — это тест принадлежности одного membership_choice.
Для вычисления теста принадлежности с использованием in, у которого membership_choice_list имеет один membership_choice, *tested_*simple_expression и membership_choice вычисляются в произвольном порядке; результат — результат теста принадлежности отдельного элемента для membership_choice.
Для вычисления теста принадлежности с использованием in, у которого membership_choice_list имеет более одного membership_choice, *tested_*simple_expression теста принадлежности вычисляется в первую очередь, а результат операции эквивалентен результату последовательности, состоящей из теста принадлежности отдельного элемента для каждого membership_choice, объединённого с условным оператором или иначе.
Тест принадлежности отдельного элемента даёт результат True, если:
- membership_choice является *choice_*simple_expression, и *tested_*simple_expression равно значению membership_choice. Если проверяемый тип — тип записи или расширение записи, или ограничен в месте, где происходит тест принадлежности, тест использует примитивное равенство для типа; в противном случае тест использует предопределённое равенство.
- membership_choice — range, и значение *tested_*simple_expression принадлежит заданному range.
- membership_choice — subtype_mark, проверяемый тип скалярный, значение *tested_*simple_expression принадлежит диапазону именованного подтипа, и значение удовлетворяет предикатам именованного подтипа.
- membership_choice — subtype_mark, проверяемый тип не скалярный, значение *tested_*simple_expression удовлетворяет любым ограничениям именованного подтипа, значение удовлетворяет предикатам именованного подтипа, и:
если тип *tested_*simple_expression является универсальным типом, значение имеет тег, который идентифицирует тип, охватываемый проверяемым типом;
если проверяемый тип — тип доступа, а именованный подтип исключает null, значение *tested_*simple_expression не равно null;
если проверяемый тип — это общий тип доступа к объекту, тип *tested_*simple_expression преобразуем к проверяемому типу и его уровень доступности не глубже, чем проверяемого типа; далее, если целевой тип проверяемого типа помечен, а *tested_*simple_expression ненулевой, тег объекта, обозначенного значением *tested_*simple_expression, охватывается целевым типом проверяемого типа.
В противном случае тест возвращает значение False.
Тест принадлежности с использованием not in даёт результат, обратный соответствующему тесту принадлежности с использованием in.
Требования к реализации
Для всех не ограниченных типов, объявленных в пакетах, определяемых языком, операторы «=» и «/=” типа должны вести себя так, как если бы они были предопределенными операторами равенства для целей равенства составных типов и формальных типов обобщений.
Этот абзац был удалён.
ПРИМЕЧАНИЕ. Если составной тип имеет компоненты, зависящие от дискриминаторов, два значения этого типа имеют соответствующие компоненты только в том случае, если их дискриминаторы равны. Два ненулевых массива имеют соответствующие компоненты только в том случае, если длина каждого измерения одинакова для обоих.
Примеры
Примеры выражений, включающих операторы сравнения и тесты принадлежности:
X /= Y
A_String = "A" -- True (см. 3.3.1)
"" < A_String and A_String < "Aa" -- True
A_String < "Bb" and A_String < "A " -- True
"" < A_String and A_String < "Aa" -- True
A_String < "Bb" and A_String < "A " -- True
My_Car = null -- True, если My_Car было установлено в null (см. 3.10.1)
My_Car = Your_Car -- True, если мы оба делим одну и ту же машину
My_Car.all = Your_Car.all -- True, если две машины идентичны
My_Car = Your_Car -- True, если мы оба делим одну и ту же машину
My_Car.all = Your_Car.all -- True, если две машины идентичны
N not in 1 .. 10 -- тест принадлежности к диапазону
Today in Mon .. Fri -- тест принадлежности к диапазону
Today in Weekday -- тест принадлежности к подтипу (см. 3.5.1)
Card in Clubs | Spades -- тест принадлежности к списку (см. 3.5.1)
Archive in Disk_Unit -- тест принадлежности к подтипу (см. 3.8.1)
Tree.all in Addition'Class -- тест принадлежности к классу (см. 3.9.1)
Today in Mon .. Fri -- тест принадлежности к диапазону
Today in Weekday -- тест принадлежности к подтипу (см. 3.5.1)
Card in Clubs | Spades -- тест принадлежности к списку (см. 3.5.1)
Archive in Disk_Unit -- тест принадлежности к подтипу (см. 3.8.1)
Tree.all in Addition'Class -- тест принадлежности к классу (см. 3.9.1)