Перечисляемый тип | это... Что такое Перечисляемый тип? (original) (raw)
Перечисляемый тип (сокращённо перечисле́ние, англ. enumeration, enumerated type) — в программировании тип данных, чьё множество значений представляет собой ограниченный список идентификаторов.
Содержание
- 1 Описание и использование
- 2 Реализация
- 3 Критика
- 4 Описание перечислений в различных языках
- 5 Примечания
Описание и использование
Перечисляемый тип определяется как набор идентификаторов, с точки зрения языка играющих ту же роль, что и обычные именованные константы, но связанные с этим типом. Классическое описание типа-перечисления в языке Паскаль выглядит следующим образом:
type Cardsuit = (clubs, diamonds, hearts, spades);
Здесь производится объявление типа данных Cardsuit (карточная масть), значениями которого может быть любая из четырёх перечисленных констант. Переменная типа Cardsuit
может принимать одно из значений clubs, diamonds, hearts, spades
, допускается сравнение значений типа перечисление на равенство или неравенство, а также использование их в операторах выбора (в Паскале — case
) в качестве значений, идентифицирующих варианты.
Использование перечислений позволяет сделать исходные коды программ более читаемыми, так как позволяют заменить «магические числа», кодирующие определённые значения, на читаемые имена.
На базе перечислений в некоторых языках могут создаваться типы-множества. В таких случаях множество понимается (и описывается) как неупорядоченный набор уникальных значений типа-перечисления.
Перечисляемый тип может использоваться в объявлениях переменных и формальных параметров функций (процедур, методов). Значения перечислимого типа могут присваиваться соответствующим переменным и передаваться через параметры соответствующих типов в функции. Кроме того, всегда поддерживается сравнение значений перечислимого типа на равенство и неравенство. Некоторые языки поддерживают также другие операции сравнения для значений перечислимых типов. Результат сравнения двух перечислимых значений в таких случаях определяется, как правило, порядком следования этих значений в объявлении типов — значение, которое в объявлении типа встречается раньше, считается «меньше» значения, встречающегося позже. Иногда перечислимый тип или некоторый диапазон значений перечислимого типа также может быть использован в качестве типа индекса для массива. В этом случае для каждого значения выбранного диапазона в массиве имеется один элемент, а реальный порядок следования элементов соответствует порядку следования значений в объявлении типа.
Реализация
Обычно в процессе компиляции значения перечислений представляются при помощи целых чисел. В зависимости от конкретного языка программирования такое представление может быть либо полностью скрыто от программиста, либо доступно ему с помощью тех или иных «обходных манёвров» (например, принудительного преобразования значения типа перечисление к значению типа «целое число»), либо даже управляемо программистом (в таких случаях программист имеет возможность явно указать, какими числами будут кодироваться все или некоторые значения типа-перечисления). У всех вариантов есть свои положительные и отрицательные стороны. С одной стороны, возможность использования числовых значений констант, составляющих тип-перечисление, особенно при злоупотреблении ею, лишает смысла использование этих типов и создаёт опасность появления ошибок (когда используются числовые значения, для которых в типе нет соответствующих констант). С другой стороны, явное управление значениями даёт некоторые дополнительные возможности. Например, позволяет использовать типы-перечисления при организации интерфейса с модулями, написанными на других языках, если они используют или возвращают кодированные целыми числами значения из некоторого предопределённого набора.
Ещё одна возможность, которую дают перечислимые типы на уровне реализации языка — экономия памяти. При небольшом объёме типа-перечисления для хранения значения этого типа достаточно нескольких битов (вышеприведённый тип Cardsuit
требует всего два бита на значение, в то время как стандартное целое число на большинстве используемых архитектур занимает 32 бита — в 16 раз больше), и компилятор может использовать этот факт для уплотнения хранения данных в памяти. Это может быть особенно важно, если несколько значений типов-перечислений хранятся в одной записи — уплотнение записей при обработке больших их количеств может освободить много памяти. Правда, необходимо отметить, что компиляторы обычно не реализуют эту возможность, по крайней мере, в последнее время, когда компьютерная память существенно подешевела.
Критика
Тип перечисление является традиционным для развитых языков программирования, используется достаточно широко и часто воспринимается как нечто само собой разумеющееся. Тем не менее, этот тип также не обходится без критики со стороны теоретиков и практиков программирования. Так, при разработке языка программирования Оберон перечислимые типы попали в список возможностей, которые были удалены из языка. Никлаус Вирт, разработчик языка, назвал следующие причины:
- «во всё возрастающем числе программ непродуманное использование перечислений … приводит к демографическому взрыву среди типов, что, в свою очередь, ведёт не к ясности программ, а к многословию»[1];
- когда тип перечисление экспортируется модулем (то есть становится частью интерфейса) нарушается общее правило — команда экспорта типа экспортирует одновременно все его элементы, тогда как для всех остальных типов экспорт типа скрывает его внутреннюю структуру;
- с точки зрения обеспечения удобочитаемости программ ничто не мешает вместо перечислимого типа использовать просто группу совместно определённых именованных констант, особенно при наличии таких языковых механизмов, как модули или классы.
С другой стороны, например, в Java, первоначально не содержащей перечислимого типа, этот тип был впоследствии введён из соображений не только удобства, но и надёжности: проблема использования вместо перечислений групп именованных констант в том, что отсутствует контроль со стороны компилятора как за уникальностью значений констант, так и за возможностью случайного присваивания переменным значений, не соответствующих ни одной из этих констант.
Описание перечислений в различных языках
Ada
В языке Ada перечисления задаются с помощью ключевого слова is
и последующего списка значений через запятую:
type Cardsuit is (clubs, diamonds, hearts, spades);
C и языки с C-подобным синтаксисом
Первоначальный K&R(сокр.Керниган&Ритчи - создатели языка) диалект C не имел перечисляемых типов, однако они были добавлены в стандарте ANSI C.
enum cardsuit { CLUBS, DIAMONDS, HEARTS, SPADES };
Динамические языки слабой типизации с C-подобным синтаксисом (напр., perl или JavaScript), как правило, не имеют перечислений.
C++
Перечисления в языке C++ прямо наследуют поведение перечислений языка C, за исключением того, что перечисляемый тип в C++ — настоящий тип, и ключевое слово enum
используется только при объявлении такого типа. Если при обработке параметра являющегося перечислением, какое-либо значение из перечисления не обрабатывается (например один из элементов перечисления забыли обработать в конструкции switch
), то компилятор может выдать предупреждение о забытом значении. [2]
C#
enum Cardsuit { Clubs, Diamonds, Spades, Hearts };
Java
В первоначальной Java перечислений не было, вместо них предлагалось использовать классы со статическими константами. Начиная с версии 5 (1.5) перечисления были введены в язык, они представляют собой полноценный класс, в который можно добавлять произвольное количество полей и методов. Перечисления были введены для улучшенного контроля за типобезопасностью. [3]
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }
Haskell
В некоторых языках программирования (например, в языке Haskell) при помощи Алгебраических типов можно эмулировать перечисления. Например, так кодируется булевский тип, содержащий два идентификатора для представления значений истинности:
data Bool = False | True
Примечания
![]() |
|
---|---|
Неинтерпретируемые | Бит • Ниббл • Байт • Трит • Трайт • Слово |
Числовые | Целый • С фиксированной запятой • С плавающей запятой • Рациональный • Комплексный • Длинный • Интервальный |
Текстовые | Символьный • Строковый |
Указатель | Адрес • Ссылка |
Композитные | Алгебраический тип данных (обобщённый) • Массив • Ассоциативный массив • Класс • Список • Кортеж • Объект • Option type • Product • Структура • Множество • Объединение (tagged) |
Другие | Логический • Низший тип • Коллекция • Перечисляемый тип • Исключение • First-class function • Opaque data type • Recursive data type • Семафор • Поток • Высший тип • Type class • Unit type • Void |
Связанные темы | Абстрактный тип данных • Структура данных • Интерфейс • Kind (type theory) • Примитивный тип • Subtyping • Шаблоны C++ • Конструктор типа • Parametric polymorphism |