枚举类型定义了一个有序的值的集合,这些值简单地用标识符列表表示,并且不需要有固定含义。声明枚举类型的语法是:
type typeName = (val_1, …, _val_n)
这里的类型名_typeName
和每个值val都是有效标识符。例如,声明
type Suit = (Club, Diamond, Heart, Spade);
定义了一个叫做Suit的枚举类型,Suit类型中可能的值是ClubDiamondHeartSpade,这里,Ord(Club)返回0,Ord(Diamond)返回1,等等。

声明枚举类型时,可以声明每个值val作为类型typeName的常量。如果val标识符在相同的作用域中已经用于其他含义,那么将发生命名冲突。例如,假定声明了类型
type TSound = (Click, Clack, Clock);
不幸的是,Click也已作为TControl极其才VCL和/或CLX中的所有后裔的方法名被声明。因此,如果编写一个应用程序并创建一个事件句柄如
procedure TForm1.DBGrid1Enter(Sender: TObject);
var Thing: TSound;
begin

Thing := Click;

end;
这将导致编译错误,因为编译器将把这里的Click作为对TFormClick方法的引用来解释。当然,可以通过限定词来回避,这里假如TSound是在单元MyUnit中声明的,那么可以写成
Thing := MyUnit.Click;
更好的解决办法是,选择不会与其他标识符冲突的常量名称。例如:
type
TSound = (tsClick, tsClack, tsClock);
TMyColor = (mcRed, mcBlue, mcGreen, mcYellow, mcOrange);
Answer = (ansYes, ansNo, ansMaybe);

可以使用(_val_1, …, _val_n)结构直接声明枚举类型,例如
var MyCard: (Club, Diamond, Heart, Spade);
但这样就不能在相同的作用域中再声明另一个变量使其具有相同的标识符。如
var Card1: (Club, Diamond, Heart, Spade);
var Card2: (Club, Diamond, Heart, Spade);
这将产生编译错误。而声明
var Card1, Card2: (Club, Diamond, Heart, Spade);
可以通过编译,相当于
type Suit = (Club, Diamond, Heart, Spade);
var
Card1: Suit;
Card2: Suit;

明确指定序号的枚举类型

缺省情况下,枚举值的序号从0开始,并且接下来的序列对应类型声明中相应的标识符。可以通过对部分或全部枚举值明确指定序号来忽略缺省序号。要对枚举值指定序号,则要再标识符后跟随 = constantExpression,这里的constantExpression是一个可以计算得到整数的常量表达式。例如
type Size = (Small = 5, Medium = 10, Large = Small + Medium);
定义了一个叫做Size的枚举类型,该类型可能的值包括SmallMediumLarge,这里Ord(Small)返回5,Ord(Medium)返回10,Ord(Large)返回15。

实际上,一个枚举类型就是一个子界,该子界的最小值和最大值对应于声明中常量的最小序号和最大序号。再上面的例子中,Size类型有11个可能的值,这些值的范围是5到15。(因此,类型array[Size] of Char表示的是一个含有11个字符的数组。)在这些值中,只有三个有名字,但其他的值通过类型转换和一些例程(如PredSuccIncDec)也是可访问的。下面的例子中,在Size类型范围之内的匿名值被赋给了变量X。
var X: Size;
X := Small; // Ord(X) = 5
X := Size(6); // Ord(X) = 6
Inc(X); // Ord(X) = 7

在枚举类型声明中,任何没有明确给出序号的值,其缺省序号比其前驱值大1。如果第一个值没有被指定序号,那么其序号为0。因此,对于给出的声明
type SomeEnum = (e1, e2, e3 = 1);
枚举类型SomeEnum仅有两个可能的值:Ord(e1) 返回0,Ord(e2)返回1,并且Ord(e3)也返回1,因为e2和e3具有相同的序号,所以他们表示相同的值。