Запись может иметь вариантную часть. Это означает, что можно задать в пределах одного типа несколько различных структур. Непосредственный выбор структуры будет определяться контекстом или каким-либо сигнальным значением. Вариантные поля указываются после того, как перечислены поля фиксированные. Вариантные поля и оформляются особым образом. Рассмотрим пример описания типа VRecType — записи с вариантами.
| TYPE
| VRecType = RECORD { тип записи с вариантами }
| Number : Byte; { номер измерения длины }
| case Measure : Char of { признак единицы длины }
| 'д','Д' (inches : Word); {длина в дюймах}
| 'с','С' (cantimeters : LongInt); { длина в см }
| '?' (Comment1, Comment2 : String[16]) { тексты }
| END;
- 138 -
В данном случае в записи имеется обычное фиксированное поле Number. Другое фиксированное поле — Measure. Оно всегда присутствует в структуре записи, но параллельно с этим выполняет роль селектора (иногда его называют полем тега от английского «Tag Field»). Поле-селектор обрамляется словами CASE и OF, и за ним следует перечисление вариантов третьего поля, взятых в круглые скобки. Какой именно вариант поля будет принят при работе с записью, обозначается содержимым селектора (Measure в приведенном примере). Значения селектора, указывающие на тот или иной вариант, записываются перед соответствующими вариантами (аналогично тому, как это происходит в операторе выбора CASE). Пусть объявлена переменная VRec типа VRecType. В зависимости от содержимого поля-селектора Measure будут корректно работать поля записи, показанные в табл. 7.1.
Таблица 7.1
Measure = | 'д' или 'Д' | 'с' или 'С' | '?' | прочие |
Поля Vrec, к которым обращение будет корректным. | Number Measure inches | Number Measure cantimeters | Number Measure Comment1 Comment2 | Number Measure |
Важно понимать, что в любое время доступны поля только одного из всех возможных вариантов, описанных в типе (или ни одно из них). Все варианты располагаются в одном и том же месте памяти при хранении, а размер этого места определяется самым объемным из вариантов. Так, запись типа VRecType будет храниться как 36 байт (1 байт — Number, 1 байт — Measure и 2*(16+1) байт на самый длинный вариант — с типом поля String[16]) независимо от выбора варианта.
Следствием такого способа хранения вариантов является опасность наложения значений при неправильных действиях с записями:
| VAR
| VRec : VRecType;
| BEGIN
| VRec.Measure := 'Д'; { выбираем дюймы }
| VRec.Inches := 32; { запишем 32 дюйма }
{ Теперь, не изменяя значения поля Comment1, опросим его: }
| WriteLn(VRec.Comment1);
| WriteLn(VRec.Comment1);