Выбрать главу

| TYPE

| Personages = ( NifNif, NufNuf, NafNaf );

| Test = ( Level0, Level1, Level2, Level4, Level5);

| MusicCard = ( IBM, Yamaha, ATARI, other, None);

| Boolean3 = (false_, Nolnfo_, true_);

Значения в скобках — это значения новых типов. Можно теперь объявлять переменные этих типов, а их значениями можно индексировать массивы или организовывать по ним циклы. Но всегда переменная такого типа сможет содержать только те значения, которые указаны в его перечислении.

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

Идентификаторы не могут повторяться в одной программе. Заметьте, как введен тип Boolean3 для моделирования трехзначной логики: чтобы избежать использования уже задействованных имен True и False, они чуть-чуть видоизменены. Регистр написания идентификаторов по-прежнему не играет роли. Максимальное число элементов в одном вводимом перечислении равно 65535.

Применение вводимых перечислимых типов имеет ряд преимуществ:

1) улучшается смысловая читаемость программы;

2) более четко проводится контроль значений;

3) перечислимые типы имеют очень компактное машинное представление.

Недостатком применения перечислимых типов является то, что значения из перечислимого типа (атомы) не могут быть выведены на экран или принтер и не могут быть явно введены с клавиатуры. Бороться с этим недостатком можно, но посредством не очень красивых приемов. Обычно, чтобы все-таки иметь возможность вывода на экран, вводят массивы, проиндексированные атомами. Каждый их элемент есть строковое написание соответствующего атома (например, для атома NoInfo_ — строка 'Nolnfo_').

- 67 -

Для работы с перечислимыми типами в Турбо Паскале используются общепринятые функции Ord, Pred и Succ. Рассмотрим их действие.

Любой перечислимый тип имеет внутреннюю нумерацию. Первый элемент всегда имеет номер 0; второй — номер 1 и т.д. Порядок нумерации соответствует порядку перечисления. Номер каждого элемента можно получить функцией Ord(X) : LongInt, возвращающей целое число в формате длинного целого, где X — значение перечислимого типа или содержащая его переменная. Так, для введенного выше типа Test:

Ord(Level0) даст 0,

Ord(Level1) даст 1,

...

Ord(Level5) даст 5.

Применительно к целым типам функция Ord не имеет особого смысла и возвращает значение аргумента:

Ord(0) = 0

Ord(-100) =-100

но для значений Char она вернет их код:

Ord('0') = 48,

Ord(' ') = 32,

Ord('Б') = 129.

Для логических значений

Ord(False) = 0 и Ord( True ) = 1.

Обратной функции для извлечения значения по его порядковому номеру в языке нет, хотя выражение вида

X : = ИмяПеречислимогоТипа(ПорядковыйНомер)

запишет в X значение, соответствующее заданному порядковому номеру элемента перечисления. Кроме этого, имеются две функции последовательного перебора значений перечислимого типа:

Succ(X) — возвращает следующее за X значение в перечислимом типе;

Pred(X) — возвращает предыдущее значение в перечислимом типе.

Так, для нашего типа Boolеаn3

Succ(false_) = noinfo_ = Pred( true_).

Функции Succ и Pred применимы и к значениям целочисленных типов:

- 68 -

Succ(15) = 16, Succ(-15) = -14,

Pred(15) = 14, Pred(-15) = -16.

и очень эффективно работают в выражениях вида (N-1)*N*(N+1), которые могут быть переписаны как Pred(N)*N*Succ(N).

Не определены (запрещены) значения:

Succ(последний элемент перечисления)

и

Pred(первый элемент перечисления).

Поскольку перечислимые значения упорядочены, их можно сравнивать. Из двух значений большим является то, у которого больше порядковый номер (но это сравнение должно быть в пределах одного и того же типа!), т.е. выполняется:

True > False

в типе Boolean,

NoInfo_ < true_

в типе Boolean3,

'z' > 'a'

в типе Char.

Знаки сравнения могут быть и нестрогими.

4.1.8. Ограниченные типы (диапазоны)

Еще одним вводимым типом языка является диапазон. Используя его, мы можем определить тип, который будет содержать значения только из ограниченного поддиапазона некоего базового типа. Базовым типом, из которого вычленяются диапазоны, может быть любой целочисленный тип, тип Char и любой из введенных программистом перечислимых типов.

Для введения нового типа — диапазона — надо в блоке описания типов TYPE указать имя этого типа и границы диапазона через две точки подряд:

| TYPE

| Century = 1..20; { диапазон целочисленного типа }

| CapsLetters = 'А'..'Я'; { заглавные буквы из типа Char }

| TestOK = Level3..Level5; { часть перечислимого типа Test }

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

- 69 -

Это еще больше усиливает контроль данных при выполнении программы. Значения переменных типа «диапазон» могут выводиться на экран и вводиться с клавиатуры, только если этот диапазон взят из базового типа, выводимого на экран или вводимого с клавиатуры. В приведенном примере сугубо «внутренними» значениями будут только значения, принадлежащие к типу TestOK, как диапазону невыводимого перечислимого типа Test. Будет ошибкой задать нижнее значение диапазона большим, чем верхнее.

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

| TYPE

| IntervalNo = (2*3+2)*2 .. (5+123); {неверно! }

| IntervalYes = 2*(2*3+2) .. (5+123); { правильно }

4.2. Сложные типы языка

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

Тип «массив» определяется конструкцией

Array [диапазон] of ТипЭлементов;

Диапазон в квадратных скобках указывает значения индексов первого и последнего элемента в структуре. Примеры объявления типов:

| TYPE

| Array01to10 = Array[ 1..10] of Real;

| Array11to20 = Array [11..20] of Real;

Здесь мы вводим два типа. Они совершенно одинаковы по структуре, но по-разному нумеруют свои элементы. Оба типа содержат наборы из десяти значений типа Real.

Пусть определены переменные именно таких типов (скажем, a01to10 и a11to20). Доступ к i-му элементу массивов осуществляется через запись индекса в квадратных скобках сразу за именем массива: a01to10[i] или a11to20[i].

Возможно объявление таких конструкций, как массив массивов (это будет, по сути, матрица) или других структур. Подробнее массивы будут рассмотрены в разд. 7.1 «Массивы (Array) и работа с ними».

- 70 -

Другим сложным типом является множество, конструируемое специальной фразой

Set of БазовыйПеречислимыйТип.

Данные типа «множество» — это наборы значений некоего базового перечислимого типа, перечисленные через запятую в квадратных скобках. Так, если базовым считать введенный ранее перечислимый тип Test, то значение типа

Set of Test

может содержать произвольные выборки значений типа Test:

[Level0]

[Level3, Leve4]

[Level1..Level5],

и т.п., а также

[] — пустое множество.

Множество отличается от массива тем, что не надо заранее указывать количество элементов в нем, используя индексацию. Множество может расширяться или сокращаться по ходу программы. В Паскале определены операции над множествами, аналогичные математическим: объединение множеств, поиск пересечения их (взятие разности множеств), выявление подмножеств и др. Излишне говорить, что такой тип данных существенно расширяет гибкость языка. Подробно множества описываются в разд. 7.3 «Тип «множество» (Set). Операции с множествами».