Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> Delphi / Pascal -> Перечислимые типы данных, определяемые пользователем


Перечислимые типы данных, определяемые пользователем

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

Определение

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

Назначение
Перечислимые типы очень похожи на целочисленные типы данных. Кое-кто может задаться вопросом: "А зачем это все нужно, если и так можно пользоваться целочисленными типами данных?" Предположим, что нам нужно определить состояние лифта. Возможными состояниями лифта являются: "стоит", "едет", "отключен". Можно обозначить каждое из состояний значениями 1, 2, 3 и оперировать ими. Какие у нас тут появляются проблемы?

Во-первых - не наглядно. Посмотрит человек со стороны, и ему еще придется вникать, что 1 это "стоит", а 3 это "отключен", и почему не наоборот. Да и самому можно запутаться.

Во-вторых - есть потенциальное место для ошибок. Что если целочисленной переменной, которая обозначает состояние лифта, где-нибудь присвоят значение 4? Что это будет обозначать для кода, обрабатывающего это значение? Что с ним произойдет? Он отработает, но выдаст неверный результат, или программа просто "вывалится" с ошибкой? Придется в каждом месте, где используется эта переменная писать код проверки на правильность значения. А если у нас добавиться еще одно состояние "авария", то придется исправлять код проверяющий правильность значения.

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

Синтаксис
EnumeratedTypeName=(ListOfValues);
  • EnumeratedTypeName - Идентификатор перечислимого типа данных.
  • ListOfValues - Описание перечислимого типа. Список идентификаторов значений, принадлежащих к указанному типу данных.
Список идентификаторов значений, это простое перечисление идентификаторов значений, разделенных запятой. Список идентификаторов не может быть пустым.

Value0, Value1, Value2, …, ValueN

Примеры описания перечислимых типов

Светофор

Предположим мы хотим иметь перечислимый тип данных, обозначающий цвет светофора (о том, что светофор бывает выключенным, на время забудем). Как мы все знаем, светофор может светить одним из следующих цветов: красный, желтый, зеленый. Обозначим каждый цвет своим идентификатором: Red, Yellow, Green. Назовем перечислимый тип данных, определяющий возможные цвета светофора, как TSemaphoreColor. Описание нашего типа данных будет выглядеть так:

type
	TSemaphoreColor=(Red, Yellow, Green);

NB! Не забываем, что секция описания типов данных начинается с ключевого слова type, см. лекцию 2 "Переменные, типы данных и константы".

Радуга

Вспоминая известную фразу "Каждый охотник желает знать, где сидит фазан", определяем перечислимый тип данных TRainbow.

type
	TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

Еще разные примеры

type
	TGender=(Male, Female);
	TCar=(Mercedess, BMW, Toyota, TVR, Mazda); // марки взяты с потолка :-)
	TPlayerCharacterClass=(Fighter, Cleric, Rogue, Wizard);

Порядковые номера

Каждое значение в перечислимом типе имеет свой порядковый номер. Первое значение имеет порядковый номер 0. Второе значение имеет порядковый номер 1 и т.д. Порядковые номера назначаются компилятором в том порядке, в котором идентификаторы перечислены в описании типа.

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

Value0=NumberOfValue0, Value1=NumberOfValue1, …, ValueN=NumberOfValueN

  • NumberOfValueX - константное целочисленное выражение, задающее порядковый номер соответствующего идентификатора.
Пример

type
	TNumber=(Two=2, Three=3, Five=5, Seven=Two+Five);

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

При объявлении переменных перечислимого типа нет необходимости объявлять идентификатор типа данных. Описание перечислимого типа может быть использовано прямо при объявлении переменной:

var
	VariableName: (ListOfValues);

Пример

var
	Fighter:(Hornet, Tomcat, Falcon, Raptor);

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

var
	Fighter1:(Hornet, Tomcat, Falcon, Raptor);
	Fighter2:(Hornet, Tomcat, Falcon, Raptor);

Чтобы избежать ошибки компиляции следует изменить описание переменных следующим образом:

var
	Fighter1, Fighter2:(Hornet, Tomcat, Falcon, Raptor);

Операции со значениями перечислимых типов данных

В сущности, перечислимые типы данных не сильно отличаются от целочисленных типов данных.

Вычисление последующего и предыдущего значений

Функции стандартной библиотеки Succ и Pred обеспечивают получение последующего и предыдущего значений, как и для любого другого порядкового типа данных вроде Integer или Byte.

program enumdemo1;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
begin
	Color:=Succ(Yellow); {присвоим переменной Color значение,
	принадлежащее типу данных TRainBow, являющееся следующим
за Yellow.}
	{В зависимости от значения Color выведем название цвета}
	case Color of
		Red: WriteLn('Red');
		Orange: WriteLn('Orange');
		Yellow: WriteLn('Yellow');
		Green: WriteLn('Green');
		Azure: WriteLn('Azure');
		Blue: WriteLn('Blue');
		Violet: WriteLn('Violet');
	end;

	Color:=Blue; // присвоим переменной Color значение синего цвета
	Color:=Pred(Color); {присвоим переменной Color, значение цвета
                            являющегося предыдущим для текущего значения Color}

	{В зависимости от значения Color выведем название цвета}
	case Color of
		Red: WriteLn('Red');
		Orange: WriteLn('Orange');
		Yellow: WriteLn('Yellow');
		Green: WriteLn('Green');
		Azure: WriteLn('Azure');
		Blue: WriteLn('Blue');
		Violet: WriteLn('Violet');
	end;
	WriteLn('Press Enter key…');
	ReadLn;
end.

Поскольку для Red отсутствует предыдущее значение, а для Violet последующее, то попытка получить их приведет к ошибке времени выполнения. Например такой код, вызовет ошибку времени выполнения:

…
var
	Color:TRainbow;
begin
	Color:=Pred(Red);
…

Использование в контрольных выражениях в управляющих структурах

Последовательно выведем с помощью цикла for названия цветов радуги, начиная с Orange и заканчивая Azure.

program enumdemo2;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
begin
	// в цикле перебираются значения от Orange до Azure
	for Color:=Orange to Azure do
		{В зависимости от значения Color выведем название цвета}
		case Color of
			Red: WriteLn('Red');
			Orange: WriteLn('Orange');
			Yellow: WriteLn('Yellow');
			Green: WriteLn('Green');
			Azure: WriteLn('Azure');
			Blue: WriteLn('Blue');
			Violet: WriteLn('Violet');
		end;

	WriteLn('Press Enter key...');
	ReadLn;
end.

Сделаем то же самое, только с использованием цикла while. Обратите внимание на функции стандартной библиотеки Low и High. Каждая принимает в качестве единственного параметра идентификатор перечислимого типа данных и возвращает минимальное или максимальное значение, возможное для переменных данного типа.

program enumdemo3;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
begin
	{В цикле перебираются значения от минимального
	значения типа TRainbow, до максимального}
	Color:=Low(TRainbow);
	while Color<=High(TRainbow) do
		begin
			{В зависимости от значения Color выведем название цвета}
			case Color of
				Red: WriteLn('Red');
				Orange: WriteLn('Orange');
				Yellow: WriteLn('Yellow');
				Green: WriteLn('Green');
				Azure: WriteLn('Azure');
				Blue: WriteLn('Blue');
				Violet: WriteLn('Violet');
			end;
			Color:=Succ(Color); {Присвоим Color значение цвета
			следующее за текущим значением Color}
		end;
	WriteLn('Press Enter key...');
	ReadLn;
end.

В зависимости от цвета выведем, к каким цветам он относится, "холодным" или "теплым". Будем считать, что все цвета до зеленого включительно являются "теплыми". Для разнообразия будем считать цвета от "конца" к "началу", т.е. от фиолетового цвета к красному.

program enumdemo4;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
begin
	{В цикле перебираются значения от максимального
	значения типа TRainbow, до минимального}
	for Color:=High(TRainbow) downto Low(TRainbow) do
		begin
			{В зависимости от значения Color выведем название цвета}
			case Color of
				Red: Write('Red');
				Orange: Write('Orange');
				Yellow: Write('Yellow');
				Green: Write('Green');
				Azure: Write('Azure');
				Blue: Write('Blue');
				Violet: Write('Violet');
			end;
			{А затем добавим его описание, холодный или теплый.}
			if Color>Green then
				WriteLn(' is cold color.')
			else
				WriteLn(' is warm color.');
		end;
	WriteLn('Press Enter key...');
	ReadLn;
end.

Получение порядкового номера значений типа

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

program enumdemo5;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
begin
	{В цикле перебираются значения от максимального
	значения типа TRainbow, до минимального}
	for Color:=Low(TRainbow) to High(TRainbow) do
		begin
			Write('Ordinal value of ');
			{В зависимости от значения Color выведем название цвета}
			case Color of
				Red: Write('Red');
				Orange: Write('Orange');
				Yellow: Write('Yellow');
				Green: Write('Green');
				Azure: Write('Azure');
				Blue: Write('Blue');
				Violet: Write('Violet');
			end;
			{Выведем порядковый номер цвета}
			WriteLn(' is ', Ord(Color));
		end;
	WriteLn('Press Enter key...');
	ReadLn;
end.

Получение значения по его порядковому номеру

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

program enumdemo6;
{$APPTYPE CONSOLE}

type

TRainbow=(Red, Orange, Yellow, Green, Azure, Blue, Violet);

var
	Color:TRainbow;
	LowIndex, HighIndex, ColorIndex:Integer;

begin
	{Заранее вычислим минимально и максимально допустимые
	значения индекса цвета}
	LowIndex:=Ord(Low(TRainbow));
	HighIndex:=Ord(High(TRainBow));
	// выведем приглашение ко вводу
	WriteLn('Please enter index of rainbow color.');
	WriteLn('Valid values are from ', LowIndex, ' to ', HighIndex);
	// прочитаем введенное значение в переменную ColorIndex
	ReadLn(ColorIndex);
	// проверим не ввел-ли пользователь недопустимое значение
	if (ColorIndex



Автор: Andrew Fionik
Источник: www.delphikingdom.com

Ссылки по теме
Введение в Delphi 8
Работа с реестром в Delphi
Delphi и ресурсы компьютера
Советы начинающим программировать на Delphi
Структуры и базы данных, методы сортировки
 

Компьютерная документация от А до Я - Главная

 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.