Выбрать главу
Описание записей

Запись представляет собой набор элементов разных типов, каждый из которых имеет свое имя и называется полем записи. Тип записи в классическом языке Паскаль описывается следующим образом:

record

описания полей

end

где описания полей имеет такой же вид, что и раздел описания переменных без ключевого слова var.

Например:

type

Person = record

Name: string;

Age: integer;

end;

Переменные типа запись

Переменные типа запись хранят в непрерывном блоке памяти значения всех полей записи.

Для доступа к полям записей используется точечная нотация:

var p: Person;

begin

p.Name := 'Иванов';

p.Age := 20;

writeln(p); // (Иванов,20)

end.

По умолчанию процедура write выводит содержимое всех полей записи в круглых скобках через запятую.

Методы и модификаторы доступа для записей

В PascalABC.NET внутри записей допустимо определять методы и свойства, а также использовать модификаторы доступа. Таким образом, описание записи в PascalABC.NET имеет вид:

record

секция1

секция2

...

end

Каждая секция имеет вид:

модификатор доступа

описания полей

объявления или описания методов и описания свойств

Модификатор доступа в первой секции может отсутствовать, в этом случае подразумевается модификатор public (все члены открыты).

Например:

type

Person = record

private

Name: string;

Age: integer;

public

constructor Create(Name: string; Age: integer);

begin

Self.Name := Name;

Self.Age := Age;

end;

procedure Print;

end;

procedure Person.Print;

begin

writelnFormat('Имя: {0} Возраст: {1}', Name, Age);

end;

Как и в классах, методы могут описываться как внутри, так и вне тела записи. В примере выше конструктор описывается внутри записи, а метод Print объявляется внутри, а описывается вне тела записи. Метод-конструктор всегда имеет имя Create и предназначен для инициализации полей записи.

Инициализация записей

При описании переменной или константы типа запись можно использовать инициализатор записи (как и в Delphi Object Pascal):

const p: Person = (Name: 'Петрова'; Age: 18);

var p: Person := (Name: 'Иванов'; Age: 20);

Конструкторы для записей имеют тот же синтаксис, что и для классов. Однако, в отличие от классов, вызов конструктора записи не создает новый объект в динамической памяти, а только инициализирует поля записи:

var p: Person := new Person('Иванов',20);

Более традиционно в записи определяется обычный метод-процедура, традиционно с именем Init, инициализирующая поля записи:

type

Person = record

...

public

procedure Init(Name: string; Age: integer);

begin

Self.Name := Name;

Self.Age := Age;

end;

...

end;

...

var p: Person;

p.Init('Иванов',20);

В системном модуле определена также функция Rec, которая создает переменную типа запись на лету:

var p := Rec('Иванов',20);

Println(p); // (Иванов,20)

Тип этой записи - безымянный. Поля данной записи автоматически именуются Item1, Item2 и т.д.:

Println(p.Item1, p.Item2); // Иванов 20

Отличие записей от классов

Список отличий между записями и классами приводятся ниже:

* Запись представляет собой размерный тип (переменные типа запись располагаются на стеке).

* Записи нельзя наследовать; от записей также нельзя наследовать (отметим, что записи, тем не менее, могут реализовывать интерфейсы). В .NET тип записи неявно предполагается наследником типа System.ValueType и реализуется struct-типом.

* Если в записи не указан модификатор доступа, то по умолчанию подразумевается модификатор public (все члены открыты), а в классе - internal.

Вывод переменной типа запись

По умолчанию процедура write для переменной типа запись выводит содержимое всех её публичных свойств и полей в круглых скобках через запятую. Чтобы изменить это поведение, в записи следует переопределить виртуальный метод ToString класса Object - в этом случае именно он будет вызываться при выводе объекта.

Например:

type

Person = record

...

function ToString: string; override;

begin

Result := string.Format('Имя: {0} Возраст: {1}', Name, Age);

end;

end;

...

var p: Person := new Person('Иванов',20);

writeln(p); // Имя: Иванов Возраст: 20

Присваивание и передача в качестве параметров подпрограмм

Поскольку запись, в отличие от класса, представляет собой размерный тип, то присваивание записей копирует содержимое полей одной переменной-записи в другую:

d2 := d1;

Для записей принята именная эквивалентность типов: можно присваивать друг другу и передавать в качестве параметров подпрограмм записи, совпадающие только по имени.

Во избежание копирования те записи, которые содержат несколько полей, передаются в подпрограммы по ссылке. Если запись не меняется внутри подпрограммы, то используют ссылку на константу, если меняется - то ссылку на переменную:

procedure PrintPerson(const p: Person);

begin

Print(p.Name, p.Age);

end;

procedure ChangeName(var p: Person; NewName: string);

begin

p.Name := Name;

end;

Сравнение на равенство

Записи одного типа можно сравнивать на равенство, при этом записи считаются равными если значения всех полей совпадают:

type Person = record

name: string;

age: integer;

end;

var p1,p2: Person;

begin

p1.age := 20;

p2.age := 20;

p1.name := 'Ivanov';

p2.name := 'Ivanov';

writeln(p1=p2); // True

end.

Замечание

В отличие от Delphi Object Pascal, в PascalABC.NET отсутствуют записи с вариантами.

Множества

Множество представляет собой набор элементов одного типа. Элементы множества считаются неупорядоченными; каждый элемент может входить во множество не более одного раза. Тип множества описывается следующим образом:

set of базовый тип

В качестве базового может быть любой тип, в том числе строковый и классовый.

Например:

type

ByteSet = set of byte;

StringSet = set of string;

Digits = set of '0'..'9';

SeasonSet = set of (Winter,Spring,Summer,Autumn);

PersonSet = set of Person;

Элементы базового типа сравниваются на равенство следующим образом: у простых типов, строк и указателей сравниваются значения, у структурированных и у классов - значения всех элементов или полей. Однако, если поля относятся к ссылочному типу, то сравниваются только их адреса (неглубокое сравнение).