序数类型包括整数、字符、布尔、枚举、子界等类型。序数类型定义了一个有序的值的集合,集合中的每个值(除第一个)都有一个唯一的前驱值,每个值(除最后一个)都有一个唯一的后继值。此外,每个值都有一个序号,类型中的序号决定值在类型中的顺序。大多数情况下,如果一个值的序号为n,那么它的前驱值的序号为 n - 1,后继值的序号为 n + 1。
- 对于整数类型,值的序号就是其自身整数值。
- 子界类型保留了其基类型的序号。
- 对于其他序数类型,默认情况下,第一个值的序号为0,下一个为1,等等。枚举类型可以明确地忽略这一默认情况。
- 一些预定义函数作用于序数类型和序数类型标识符,下面是最重要的几个:
函数
参数 | 返回值 | 备注 | |
---|---|---|---|
Ord | 序数表达式 | 表达式的值的序号 | 不要使用Int64类型参数(见编者注中的Ord函数中不要使用Int64类型参数) |
Pred | 序数表达式 | 表达式的值的前驱值 | 不要用于具有write过程的的属性 |
Succ | 序数表达式 | 表达式的值的后继值 | 不要用于具有write过程的的属性 |
High | 序数类型标识符或序数类型变量 | 类型中的最大值 | 也可以作用于短串和数组 |
Low | 序数类型标识符或序数类型变量 | 类型中的最小值 | 也可以作用于短串和数组 |
例如,High(Byte)返回255,因为Byte类型的最大值是255;Succ(2)返回3,因为3是2的后继。
标准过程Inc和Dec分别对序数变量递增和递减。例如对于序数变量I,Inc(I)等价于I := Succ(I),如果I是一个整数变量,还等价于I := I + 1。
编者注
序数临界值的操作
对序数类型进行Pred、Succ、Inc、Dec等操作,需要注意适用范围。下面两个例子说明了一些特点:
范例一:
var
B: Byte;
begin
B := 255;
B := Succ(B); { 执行后 B = 0 }
B := 0;
B := Pred(B); { 执行后 B = 255 }
B := 255;
Inc(B); { 执行后 B = 0 }
B := 0;
Dec(B); { 执行后 B = 255 }
…
end;
范例二:
type
TWeek = (wMon, wTue, wWed, wThu, wFri, wSat, wSun);
{ 序号对应于 0..6 }
…
var
D: TWeek;
begin
D := wSun;
D := Succ(D); { 执行后 D 越界,序号为 7 }
D := Pred(D); { 执行后 D = wSun }
D := wMon;
D := Pred(D); { 执行后 D 越界,序号为 255 }
D := wSun;
Inc(D); { 执行后 D 越界,序号为 7 }
D := wMon;
Dec(D); { 执行后 D 越界,序号为255 }
…
end;
从上面的范例中可以看出,Succ函数和Inc过程实际上是简单地对序号增加,而Pred函数和Dec过程则相反。在范例一中,由于B是Byte类型,占用一个字节的内存,因此在对其进行递增和递减时,值0和255可以被视为是相邻的(即可以视为:0的前驱是255,255的后继是0)。在范例二中,TWeek类型的变量D,也占用一个字节的内存(因为枚举元素共7个,所以该类型最多占用一个字节;而如果枚举的元素数量在256和65535之间,那么将为该类型分配2个字节,序号默认也从0开始;等等),而在执行递增和递减操作时,并没有自动将0和6视为相邻,而是作为0..255序号序列的一部分。因此,对于序数类型中临界值的前驱和后继,需要小心处理。
Ord函数中不要使用Int64类型参数
请看下面的代码:
var
I: Int64;
X: Int64;
begin
I := Int64(4294967296) + 1234567;
ShowMessage(IntToStr(I));//显示的是:4296201863
X := Ord(I);//执行后X得到的并不是预期的序号
ShowMessage(IntToStr(X));//显示的是:1234567
end;
也许这一不足将在Object Pascal未来的版本中得到弥补,尽管事实上也没有太大的必要性。