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

TOP-10 программ
Symantec Norton Ghost 9.0
Partition Magic 8.0.2 Pro
Xilisoft 3GP Video Converter v3.1.7.0616b
Norton AntiVirus 2005
Xilisoft 3GP Video Converter v2.1.52.831b
Антивирус Касперского Personal 5.0.303 beta 2
RAR Password Cracker 4.12
ABBYY PDF Transformer v1.00.820
MP3 To Ringtone Gold v3.02
Mobtime Cell Phone Manager v5.3.1
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 
 

   Программирование -> 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
Структуры и базы данных, методы сортировки
 

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

 
Популярные книги

Технология программирования на C++. Начальный курс

Подробнее

Photoshop CS2. Настоящий самоучитель

Подробнее

SQL для "чайников", 5-е издание

Подробнее

 

 
Новости ИТ
01.12.2008  Buffalo выпустил миниатюрные USB-накопители
01.12.2008  VENTO TA-U1 - стильный корпус представлен Asus
01.12.2008  Fujitsu-Siemens выпускает в продажу внешний ускоритель для ноутбуков
01.12.2008  Оригинальные чехлы для ноутбуков от Choiix
01.12.2008  Опубликован код драйвера для беспроводных карт Atheros
01.12.2008  Лучший блог 2008
01.12.2008  Linux запустили на Apple iPhone
01.12.2008  LG KC780
01.12.2008  MSI дополнит линейку Wind-нетбуков двумя моделями
01.12.2008  Nikon D3X - 24,5 млн пикселей для профессионалов
01.12.2008  Киловаттник HIPER M1000 с КПД выше 85%
01.12.2008  AMD впервые снизила цены линейки Radeon HD 4800
01.12.2008  Чистильщики: Wise Registry Cleaner v.3.8.2
01.12.2008  Антивирусы: RemoveIT Pro v4 SE (30.11.2008)
01.12.2008  Корпус ASUS Vento TA-U1 можно поставить вместо новогодней ёлки
01.12.2008  Диагностика: PC Wizard 2008 v.1.871
01.12.2008  Диагностика: NextSensor v.2.7.6.0 Build 1130
01.12.2008  Тестовые приложения: PassMark BurnInTest v.6.0 Build 1000 Beta 15
01.12.2008  Неофициальные драйверы для модемов Motorola
01.12.2008  Драйверы и утилиты для сетевых хранилищ D-Link
 
Полезно

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