При работе с записями, при обращении к различным полям каждый раз приходится писать сначала имя самой записи, что не всегда удобно, если полей много. Поэтому в Паскале применяется оператор WITH:
with NEKTO do
begin
NAME := 'MANUELA'; AGE := 20;
MALADI := 'GRIP';
MARIE := true;
end.
Другими словами, в рамках оператора, помещенного внутри оператора WITH, к полям определенной переменной можно обращаться просто по имени (префикация имен опускается) (см. рис. 39() персоны необходим оператор:общей формой записи.
ющих разделов:).
Переменная
Рис. 39. Синтаксическая диаграмма оператора WITH
Особенно эффективно использовать WITH, когда речь идет о вложенных записях, т.е. таких, где поля есть тоже записи. Например, запись типа PATIENT можно расширить добавлением поля DATE, которое снова есть запись с тремя полями:
type PATIENT = record
NAME : string [10];
MALADI : string [30];
AGE : integer;
DATE : record
DEN : integer;
MESJATS : string [10];
GOD : integer;
end;
MARIE : boolean;
end;
var NEKTO : PATIENT.
При таком вложении доступ, например, к полю GOD уже должен сопровождаться указанием двух префиксных имен, например:
read (NEKTO. DATE. GOD).
Здесь уже WITH может значительно упростить работу с полями:
with NEKTO, DATE do
begin
NAME := 'MANUELA'; AGE := 20;
MALADI := 'GRIP';
DEN := 18;
MESJATS := 'MART';
GOD := 1944;
MARIE := TRUE;
end.
Оператор WITH принято называть оператором присоединения. В общем случае он выглядит так: WITH R1, R2, ..., Rn do S, что эквивалентно WITH R1 do WITH R2, R3,..., Rn do S.
Имя поля в операторе присоединения обозначает компоненту комбинированной переменной из ближайшего объединяющего оператора присоединения, в котором указана переменная с таким полем. Следовательно, если две переменные из списка комбинированных переменных оператора присоединения имеют поля, обозначенные одним и тем же именем, то внутри оператора WITH это имя обозначает поле той переменной, которая указана в списке позже.
С другой стороны, при определении некоторого комбинированного типа имена отдельных полей могут совпадать с именами обычных, простых переменных, не входящих в комбинированную переменную. Как здесь происходит отличие?
Пусть, например, имеется простая переменная AGE и поле AGE некоторой комбинированной переменной NEKTO. В этом случае их можно отличить, так как простая переменная имеет имя AGE, а переменная-поле имеет полное имя NEKTO. AGE. А что будет в операторе WITH, где префикс NEKTO опускается?
В этом случае в операторе предпочтение отдается именам полей записи, т.е. считается, что внутри оператора WITH соответствующее имя обозначает имя поля, а не имя переменной.
Проиллюстрируем этот тезис на примере. Пусть даны типы:
const N_STUD = ... ;
N_SOTR = ... ;
n = ... ;
type SEX = (M, F);
STUD = RECORD
FAM, IM, OTH : array [1..N_STUD] of string [n];
POL : SEX;
GR : 111..154;
STIP : boolean;
end;
SOTR = record
FAM, IM, OTH : array [1..N_SOTR] of string [n];
POL : SEX;
DOLGN : (LAB, ASS, STPR, DOZ, PROF);
ZARPL : integer;
end;
var X : STUD; Y : SOTR;
STIP : integer;
Тогда можно дать такой фрагмент программы:
with X, Y do
begin
IM [5] := 'ALEXANDR ';
POL := M;
STIP := true;
GR := 122;
end;
STIP := 160.
Здесь поля IM, POL относятся к переменной Y типа SOTR, так как эта переменная в списке переменных-записей заголовка WITH фигурирует после переменной X типа STUD. Кроме того, в этом фрагменте имя STIP в теле оператора WITH есть имя поля переменной Х.
Записи с вариантами
Записи, описанные ранее, – это записи с фиксированными частями. Они имеют в различных ситуациях строго определенную структуру. Однако бывают ситуации, когда нужно отказаться от этой строгой определенности. Поэтому появляются записи с вариантами.
Рассмотрим пример создания программ для введения списка библиографических ссылок. Например, научные работы могут быть оформлены в виде монографий, т.е. книг, а могут быть и журнальные публикации. Если известно, что все публикации есть книги, то это можно задать в виде следующего описания:
const MAXNOMBRE = ...
type ENTRY = record
AUTOR, TITLE, PUBLISHER, SITY : STRING [100];
YEAR : 1..9999;
end;
var REFLIST : array [1..MAXNOMBRE] of ENTRY;
Здесь ENTRY – вход, т.е. данные о какой-либо научной работе. Если же некоторые работы входят в журналы, то нужно создавать новый массив данных только для журналов и работать с этими двумя массивами, что не очень удобно. В Паскале есть возможность образовать структуру с вариантами, каждый вход которой соответствует содержанию записи. Это достигается путем введения в описание записи специального оператора CASE – переключателя, который в чем-то похож на ранее введенный, но имеет свои синтаксические и семантические отличия.
В нашем примере помимо описанного уже типа ENTRY вводим еще один переменный тип:
Это описание делится на две части: фиксированную и вариантную. Поля AUTOR, TITLE и YEAR – фиксированная часть. Остальная часть – вариантная, структура которой может меняться в пределах двух вариантов. Вариантная часть записи начинается со строки CASE, где в качестве селектора выступает не выражение, а идентификатор некоторого перечислимого типа. Элементы (компоненты) этого перечислимого типа (в нашем случае ENTRYTYPE) используются в качестве альтернативного определения записи: BOOK и MAGAZINE. В каждой альтернативе имеется свой набор полей:
BOOK: MAGAZINE:
AUTOR AUTOR
TITLE TITLE
YEAR YEAR
PUBLISHER MAGNAME
CITY VOLUME
ISSUE
Для того чтобы различать, какую из ветвей нужно выбрать для работы, в такую запись вводится так называемое поле ТЕГА (tag fild), или узловое поле. Это дополнительное поле с именем TAG имеет тип ENTRYTYPE и помещается в качестве селектора в оператор CASE-OF:
Здесь поле с именем TAG имеет тип ENTRYTYPE и принимает два значения. Если это поле имеет значение BOOK, то это ссылка на книгу, в противном случае – на журнал. Для определения составления записи с вариантами достаточно проверить значение поля TAG.
П р и м е р. Процедура печати значений записей типа ENTRY.
procedure PRINTREF (CITATION : ENTRY);
begin
with CITATION do begin
writeln (AUTOR); writeln (TITLE); writeln (YEAR);
if TAG = BOOK then
writeln (PUB,',',CITY)
else
begin writeln (MAGNAME);
writeln (VOL,',',ISSUE)
end;
end;
end;
Примечания.
1. Вариантная часть может содержать произвольное число аргументов, которые задействуются или перечислимыми типами, или произвольными порядковыми типами (интервалами).
2. Любая запись имеет только одну вариантную часть, которая должна всегда располагаться в конце описания, поэтому END оператора CASE совпадает с END всего описания.
3. Имя поля не может встречаться в двух вариантах одной записи.
4. В вариантной части могут встречаться другие новые вариантные части.
Контрольные вопросы
1. Как называются элементы, входящие в запись?
2. Почему тип RECORD называют комбинированным типом данных?
3. Почему две записи в одной программе могут иметь поля с одинаковыми именами?
4. Пусть задано:
type DATE = record
DAY : 1..31;
MONTH : (JAN, FEB, MAR, APR, MAY, JUN, JUL,
AUG, SEP, OCT, NOV, DEC);
YEAR : integer;
end;
var BD: ARRAY [1..10] of DATE, HB:DATE.
Что означают BD[3].DAY, BD[5].YEAR, HB.MONTH ?
5. Каково назначение оператора WITH?
6. Могут ли поля записи быть, в свою очередь, записями?
7. С помощью какого оператора образуются записи с вариантами?
8. Сколько вариативных полей может иметь запись с вариантами?
9. Как принято задавать значения вариативных полей?