KnigaRead.com/

W Cat - Описание языка PascalABC.NET

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн W Cat, "Описание языка PascalABC.NET" бесплатно, без регистрации.
Перейти на страницу:

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;

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

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

[список значений]

где в списке могут перечисляться через запятую либо выражения базового типа, либо (для порядковых типов) их диапазоны в виде a..b, где a и b - выражения базового типа. Например:

var

bs: ByteSet := [1,3,5,20..25];

fios: StringSet := ['Иванов','Петров','Сидорова'];

Значения в списке могут отсутствовать, тогда множество является пустым:

bs:=[];

Пустое множество совместимо по присваиванию с множеством любого типа.

Для множеств имеет место структурная эквивалентность типов.

Множества целых и множества на базе типа и его диапазонного подтипа или на базе двух диапазонных типов одного базового типа неявно преобразуются друг к другу. Если при присваивании s := s1 во множестве s1 содержатся элементы, которые не входят в диапазон значений базового типа для множества s, то они отсекаются.

Например:

var st: set of 3..9;

...

st := [1..5,8,10,12]; // в st попадут значения [3..5,8]

Операция in проверяет принадлежность элемента множеству:

if Wed in bestdays then ...

Для множеств определены операции + (объединение), - (разность), * (пересечение), = (равенство), <> (неравенство), <= (нестрогое вложение), < (строгое вложение), >= (нестрого содержит) и > (строго содержит).

Процедура write при выводе множества выводит все его элементы. Например,

write(['Иванов','Петров','Сидорова']);

выведет ['Иванов','Петров','Сидорова'], при этом данные, если это возможно, будут отсортированы по возрастанию.

Для перебора всех элементов множества можно использовать цикл foreach, данные перебираются в некотором внутреннем порядке:

foreach s: string in fios do

write(s,' ');

Для добавления элемента x к множеству s используется конструкция s += [x] или стандартная процедура Include: Include(s,x). Для удаления элемента x из множества s используется конструкция s -= [x] или стандартная процедура Exclude: Exclude(s,x).

Процедурный тип

Тип, предназначенный для хранения ссылок на процедуры или функции, называется процедурным, а переменная такого типа - процедурной переменной. Основное назначение процедурных переменных - хранение и косвенный вызов действий (функций) в ходе выполнения программы и передача их в качестве параметров.

Описание процедурного типа

Описание процедурного типа совпадает с заголовком соответствующей процедуры или функции без имени. Например:

type

ProcI = procedure (i: integer);

FunI = function (x,y: integer): integer;

Процедурной переменной можно присвоить процедуру или функцию с совместимым типом, например:

function Mult(x,y: integer): integer;

begin

Result := x*y;

end;

var f: FunI := Mult;

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

var f2: FunI := (x,y) -> x+2*y;

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

write(f(2)); // 8

write(f2(3)); // 10

Cинонимы для процедурных типов

Для наиболее распространенных процедурных типов в системном модуле определен ряд синонимов. Приведем примеры с их использованием:

var f3: IntFunc := x -> 2*x-1;

var f4: Func<integer,real> := x -> 2.5*x;

var f3: Action<real> := x -> write(x,' ');

var pr: Predicate<string> := s -> s.Length>0;

Cокращенные конструкции для процедурных типов

Для процедурных типов определены также сокращенные конструкции:

() -> T; // функция без параметров, возвращающая T

T1 -> T; // функция c параметром T1, возвращающая T

(T1,T2) -> T // функция c параметрами T1 и T2, возвращающая T

(T1,T2,T3) -> T // функция c параметрами T1, T2 и T3, возвращающая T

и т.д.

() -> (); // процедура без параметров

T1 -> T; // процедура c параметром T1

(T1,T2) -> T // процедура c параметрами T1 и T2

(T1,T2,T3) -> T // процедура c параметрами T1, T2 и T3

и т.д.

Сокращенные конструкции не могут описывать процедурные переменные с параметрами, передаваемыми по ссылке.

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

Процедурные переменные в качестве параметров

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

procedure forall(a: array of real; f: real->real);

begin

for var i := 0 to a.Length-1 do

a[i] := f(a[i]);

end;

...

forall(a,x->x*2); // умножение элементов массива на 2

forall(a,x->x+3); // увеличение элементов массива на 3

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

Операции += и -= для процедурных переменных

Процедурные переменные реализуются через делегаты .NET. Это означает, что они могут хранить несколько подпрограмм. Для добавления/отсоединения подпрограмм используются операторы += и -=:

p1 += mult2;

p1 += add3;

forall(a,p1);

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

Отсоединение неприкрепленных подпрограмм не выполняет никаких действий:

p1 -= print;

Кроме того, к процедурной переменной можно прикреплять/откреплять классовые и экземплярные методы классов. В последнем случае процедурная переменная в полях объекта запоминает некоторое состояние, которое меняется между вызовами метода, связанного с этой процедурной переменной.

Пример

type

A = class

x0: integer := 1;

h: integer := 2;

procedure PrintNext;

begin

Print(x0);

x0 *= h;

end;

end;

begin

var p: procedure;

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*