复合数据类型
复杂数据类型又称为复合数据类型,它是相对于简单数据类型(或者基本数据类型)而言的。我更愿意称之为复合数据类型,很明显它其实是由一种或者多种基本数据类型组合而成
# 枚举类型
Pascal程序不仅用于数值处理,还更广泛地用于处理非数值的数据。例如,性别、月份、星期几、颜色、单位名、学历、职业等。
# 定义
type 枚举类型标识符=(标识符1,标识符2,…,标识符n)
# 特点
枚举元素只能是标识符; 定义枚举类型时列出的所有枚举元素构成了这种枚举类型的值域(取值范围)。例如
下列类型定义是合法的:
type
days=(sun,mon,tue,wed,thu,fri,sat);
colors=(red,yellow,blue,white,black,green);
2
3
而下列类型定义是错误的:
type
colortype=('red','yellow','blue','white');
numbers=(1,3,5,7,9);
2
3
起初我在第一次使用枚举的时候直接套用Java中枚举的用法,很明显挂了。
枚举类型属于顺序类型: 根据定义类型时各枚举元素的排列顺序确定它们的序号,且序号从0开始。例如
定义type days=(sun,mon,tue,wed,thu,fri,sat); 则, ord(sun)=0,ord(mon)=1,……,以此类推。
同一个枚举元素不能出现在两个或两个以上的枚举类型定义中。如下列定义是错误的:
type
color1=(red,yellow,white); // 因为red属于枚举类型color1和 color2
color2=(blue,red,black);
2
3
4
5
6
枚举类型变量只能进行赋值运算和关系运算,不能进行算术运算和逻辑运算. 在枚举元素比较时,实际上是对其序号的比较。例如:
type
days=(sun,mon,tue,wed,thu,fri,sat);
colors=(red,yellow,blue,white,black,green);
var
color:colors;
weekday:days;
//则下面语句是合法的:
weekday:=mon;
if weekday=sun then
write('rest');
{而下面语句是不合法的:}
mon:=1; {错把枚举值当成变量名}
weekday:=blue; {枚举值blue不属于枚举变量weekday的值域}
read(color); {枚举类型变量 不能用读语句进行赋值}
write(weekday); {不能通过写语句输出枚举类型的变量值和枚举值。}
writeln(blue);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以把变量的说明与类型的定义合并在一起,这种玩法在Delphi中很常见,相当于由原来的两步合并为了一步。例如:
var
holiday,workday:(sun,mon,tue,wed,thu,fri,sat);
color:(red,yellow,blue,white,black,green);
2
3
4
5
对枚举数据的输入与输出可通过间接方式进行。输入时,一般可输入一个代码,通过程序进行转换,输出时,也只是打印出与枚举元素相对应的字符串。这在后面的例题中将有使用示例。
# 获取枚举元素
单值获取,虽然这种情况比较少见,但是不代表不能获取,很早之前我自己也不太清楚如何获取枚举中的key和value
implementation
//该单元必须引入
uses System.TypInfo;
{$R *.dfm}
type
TColors = (Red, Green, Blue);
procedure TForm1.Button1Click(Sender: TObject);
var
Colors: TColor;
Info: PTypeInfo;
EnumName: string;
EnumValue: Integer;
begin
Info := TypeInfo(TColors);
//获取value对应的名称
EnumName := GetEnumName(Info, 1);
//获取名称对应的value
EnumValue := GetEnumValue(Info, EnumName);
ShowMessage(EnumName + ',' + EnumValue.ToString);
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
遍历枚举中的值:枚举类型是一种有序类型,所以枚举类型的变量可以作为循环变量。
uses System.TypInfo;
{$R *.dfm}
type
TColors = (Red, Green, Blue);
procedure TForm1.Button1Click(Sender: TObject);
var
Colors: TColors;
Info: PTypeInfo;
EnumPoint: PTypeData;
EnumName: string;
EnumValue: Integer;
begin
Info := TypeInfo(TColors);
//获取PTypeInfo的指针对象
EnumPoint := GetTypeData(Info);
//利用TypeData中的MinValue和MaxValue函数实现遍历
for var I := EnumPoint.MinValue to EnumPoint.MaxValue do begin
EnumName := GetEnumName(Info, I);
EnumValue := GetEnumValue(Info, EnumName);
ShowMessage(EnumName + ',' + EnumValue.ToString);
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 应用实例
例:判断当前的颜色是什么。
implementation
uses System.TypInfo;
{$R *.dfm}
type
TColors = (Red, Green, Blue);
procedure TForm1.Button1Click(Sender: TObject);
var
Colors: TColors;
begin
case Colors of
Red: begin
ShowMessage('红色');
end;
Green: begin
ShowMessage('绿色');
end;
Blue: begin
ShowMessage('蓝色');
end;
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 子界类型
我个人的理解子界类型更适合用于范围的定义, 例如,人的年龄一般为1到120岁,一年中的月数为1到12月,一月中的天数为1到31天等等。
如果能在程序中对所用的变量的值域作具体规定,就便于检查出那些不合法的数据,这就能更好地保证程序运行的正确性且在一定程度上节省内存空间。
子界类型能很好解决上面的问题。其实在数组的定义中,常用到子界类型,以规定数组下标的范围。
这是Delphi特有的一种数据类型,至少在我的认知中其它语言是没有的
# 定义
type
子界类型标识符=常量1..常量2
2
3
常量1称为子界的下界,常量2称为子界的上界;所谓的上界也就是开始的边界,而下界就是结束的边界
注意事项: 下界和上界必须是同一顺序类型(该类型称为子界类型的基类型),且上界的序号必须大于下界的序号。 例如
type
age=1..100;
letter='a' ..'z';
2
3
当然了,类似于前面提到的枚举类型,它也可以把类型声明和变量声明并为一步。可以直接在变量说明中定义子界类型。
type
letter='a'..' z ';
var
ch1,ch2:letter;
2
3
4
可以合并成:
var
ch1,ch2:'a'..'d';
2
# 运算规则
凡可使用基类型的运算规则同样适用该类型的子界类型。例如,可以使用整型变量的地方,也可以使用以整型为基类型的子界类型数据。对基类型的运算规则同样适用于该类型的子界类型。例如,div,mod要求参加运算的数据为整, 因而也可以为整型的任何子界类型数据。基类型相同的不同子界类型数据可以进行混合运算。例如:设有如下说明:
var x:1..100;
y:1..500;
z:1..1000;
a:integer;
2
3
4
合法语句:
a:=Sqr(x)+y+z; z:=x+y
y:=x+z+a; 当x+y+a的值在1~500范围内时是合法的,否则会出错。
# 应用举例
例1、判断当前是周几
procedure TForm1.Button1Click(Sender: TObject);
var
Week: 1 .. 7;
begin
case Week of
1:
ShowMessage('周一');
2:
ShowMessage('周二');
3:
ShowMessage('周三');
4:
ShowMessage('周四');
5:
ShowMessage('周五');
6:
ShowMessage('周六');
7:
ShowMessage('周日');
else begin ShowMessage('非法')
end;
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 集合
在pascal中,一个集合是由具有同一有序类型的一组数据元素所组成,这一有序类型称为该集合的基类型。
有的人觉得Delphi中的集合没啥用途,这些人里面包括我自己,实际上并不是,它也有很多应用场景,例如:以前在程序中总要先从数据库中取出好多元素,然后逐个判断,现在使用集合完全可以避免这种操作
# 定义和说明
基础语法: set of 基类型;
基类型可以是任意顺序类型, 而不能是实型或其它构造类型。同时,基类型的数据的序号不得超过255。因为子界类型和枚举类型都是有序的,所以他们可以联用,如下:
function IsContainCharacter(Character: Char): Boolean;
var
Chars: set of 'A' .. 'Z';
begin
Result := Character in Chars;
end;
begin
try
Writeln(IsContainCharacter('B'));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意:因为集合的元素个数不超过256个,因此 var s:set of integer; 是错误的。
# 元素遍历
procedure ListCharacters();
var
Chars: set of char;
Str: string;
begin
Chars := ['A' .. 'J', 'a', 'm'];
for var C in Chars do begin
Str := Str + C;
end;
Writeln(Str);
end;
begin
ListCharacters;
Readln;
end.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 其他操作
type
TEnum = (One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten);
TSetEnum = set of TEnum;
//初始化
procedure TForm4.Button3Click(Sender: TObject);
begin
SetEnum := [one, Two];
SetEnum1 := [Three, Nine, Ten]
end;
//集合减少
procedure TForm4.Button5Click(Sender: TObject);
begin
SetEnum := SetEnum - [Two];
end;
//集合增加
procedure TForm4.Button6Click(Sender: TObject);
begin
SetEnum := SetEnum + [Three];
end;
//集合减少
procedure TForm4.Button7Click(Sender: TObject);
begin
Exclude(SetEnum, One);
end;
//集合增加
procedure TForm4.Button4Click(Sender: TObject);
begin
Include(SetEnum, Four);
Include(SetEnum, Ten);
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
虽然通过+ -符号可以实现对集合元素的操作,但是比较推荐的用法还是尽量使用Include和Exclude完成