Записи
Пока что все типы, с которыми мы столкнулись, имеют значения, которые нельзя разложить: каждый экземпляр представляет собой неделимый элемент данных. Теперь мы обратим наше внимание на наш первый составной тип: записи.
Записи позволяют составлять значения из значений других типов. Каждому из таких значений будет присвоено имя. Пара, состоящая из имени и значения определенного типа, называется полем или компонентой.
Объявление типа записи
Вот пример простого объявления записи:
type Date is record
-- The following declarations are
-- components of the record
Day : Integer range 1 .. 31;
Month : Months;
-- You can add custom constraints
-- on fields
Year : Integer range 1 .. 3000;
end record;
Поля во многом похожи на объявления переменных, за исключением того, что они находятся внутри определения записи. Как и при объявлениях переменных, можно указать дополнительные ограничения при предоставлении подтипа поля.
type Date is record
Day : Integer range 1 .. 31;
Month : Months := January;
-- This component has a default value
Year : Integer range 1 .. 3000 := 2012;
-- ^ Default value
end record;
Компоненты записи могут иметь значения по умолчанию. Когда объявлена переменная с типом записи, для поля с инициализацией получат заданные значения автоматически. Значение может быть задано любым выражением соответствующего типа и может вычислятся во время исполнения.
Агрегаты
Ada_Birthday : Date := (10, December, 1815);
Leap_Day_2020 : Date := (Day => 29,
Month => February,
Year => 2020);
-- ^ By name
Записи имеют удобную форму для записи значений, показанную выше. Эта нотация называется агрегированной, а сама конструкция - агрегатом. Ее можно использовать в различных контекстах, которые мы увидим на протяжении всего курса, и одним из применений является инициализация записей.
Агрегат - это список значений, разделенных запятыми и заключенных в круглые скобки. Он разрешен в любом контексте, где ожидается значение записи.
Значения для компонент можно указать позиционно, как в примере
Ada_Birthday
, или по имени, как в Leap_Day_2020
.
Разрешено сочетание позиционных и именованных значений, но вы не можете
использовать позиционную форму после появления именованной.
Извлечение компонент
Для доступа к компонентам экземпляра записи используется операция,
называемая извлечением компоненты. Она имеет форму точечной
нотации. Например, если мы объявляем переменную Some_Day
типа
записи Date
, упомянутого выше, мы можем получить доступ к компоненте
Year
, написав Some_Day.Year
.
Рассмотрим пример:
Как вы можете видеть в этом примере, мы можем использовать точечную
нотацию в выражении D.Year
или Some_Day.Year
. как для
доступа к информации компонеты, так и для ее изменения в операторе
присваивания.
Говоря конкретнее, когда мы используем D.Year
в вызове Put_Line
,
мы читаем информацию, хранящуюся в этом компоненте. Когда мы пишем
Some_Day.Year := 2001
, то перезаписываем информацию, которая
была ранее сохранена в компоненте Year
в переменной Some_Day
.
Переименование
В предыдущих главах мы обсуждали переименование подпрограмм и пакетов. Мы также можем переименовывать компоненты записи. Вместо того, чтобы каждый раз писать извлечение компоненты с использованием точечной записи, мы можем объявить псевдоним, который позволит нам получить доступ к этой компоненте. Это полезно, например, для упрощения реализации подпрограммы.
Мы можем переименовать компоненты записи, используя ключевое слово renames
в
объявлении переменной. Например:
Some_Day : Date;
Y : Integer renames Some_Day.Year;
Здесь Y
является псевдонимом, так что каждый раз, когда мы используем Y
,
мы в действительности используем компоненту Year
переменной Some_Day
.
Давайте рассмотрим полный пример:
Мы применяем переименование к двум компонентам записи Date
в реализации
процедуры Increase_Month
. Затем вместо непосредственного использования
Some_Day.Month
и Some_Day.Year
в последующих
операциях мы просто используем переименованные версии M
и Y
.
Обратите внимание, что в приведенном выше примере мы также
переименовали Months'Succ
- функцию, которая дает нам следующий
месяц - в Next
.