Ada记录的属性

2018-10-28 09:50 更新

记录则是由命名分量(named component)组成的复合类型,即具有不同属性的数据对象的集合,和C 下的结构(structure)、Pascal 下的记录(record) 类似。Ada 的记录比它们提供的功能更强,也就是限制更少。同时记录扩展(record extension)是 Ada95 中类型扩展(继承)机制的基础,使记录的地位更加突出,关于记录扩展详见 第6章 面向对象特性,为了避免重复,本章对此不作介绍。

Ada

简单记录(Simple Record)

记录类型的一般声明如下:

type record_name is
record
field name 1: type 1;
field name 2: type 2;
...
field name n: type N;
end record;

record_name 是记录类型的名称,一大堆 filed name 是记录的成员名称,紧跟其后的是该成员的数据类型。

如下面的例子:

type Id_Card is
record
Full_Name : String (1..15);
ID_Number : Positive;
Age : Positive;
Birthday : String (1..15);
Familiy_Address : String (1..15);
Family_telephone : Positive;
Job : String(1..10);
end record;
My_Card :Id_Card;

一个简单ID卡的记录,包含Full_Name,ID_Number,Age,Birthday,Familiy_Address,Family_telephone,Job 这些成员。

访问和设置记录(Access and Set Records)

使用记录的成员时,只需在记录和其成员之间用 “.” 隔开即可。如赋予My_Card中的变量 Full_Name 值 Jack Werlch:

My_Card.Full_Name := "Jack Welch ";

设置记录成员的值和设置数组给人感觉上有点类似,如:

My_Card := ("Jack Welch ", 19830519,45, "Jan 1st 1976 ",
"China ",8127271,"CEO ");

将 ( )中的值依次赋给My_Card 的成员。

相同的数据类型的成员一多,无疑会使人不大明了,因此也可以:

My_Card := ( Full_Name => "Jack Welch ",
ID_Number => 19830519,
Age => 45,
Birthday => "Jan 1st 1976 ",
Familiy_Address => "China ",
Family_telephone => 8127271;
Job => "CEO ") ;

上面两种表示法可以混用,但按位值在有名的值前面:

My_Card := ( "Jack Welch ",
19830519,
Age => 45,
Birthday => "Jan 1st 1976 ",
Familiy_Address => "China ",
Family_telephone => 8127271;
Job => "CEO ");

但如果为:

My_Card := ( Full_Name => "Jack Welch ",
ID_Number => 19830519,
Age => 45,
Birthday => "Jan 1st 1976 ",
Familiy_Address => "China ",
8127271;
"CEO ");

则是非法的。

如果几个相同类型的成员,赋予同一数值,也可以:

My_Card := ( Full_Name => "Jack Welch ",
ID_Number | Family_telephone => 19830519,
Age => 45,
Birthday => "Jan 1st 1976 ",
Familiy_Address => "China ",
Job => "CEO ");

上例我们假设 ID_Number 和 Family_telephone 值是一样的,为19830519,不同成员间用 | 隔开。

记录类型有时在声明也需要默认值:

type Id_Card is
record
Full_Name : String (1..100) := "Jack Welch ",
ID_Number : Positive := 19830519,
Age : Positive := 45,
Birthday: String (1..20) := "Jan 1st 1976 ",
Familiy_Address :String (1..100):= "China ",
Family_telephone :Positive := 8127271;
Job : String(1..10) := "CEO ");
end record;
My_Card :Id_Card;

将 Jack Welch 的资料当作了 Id_Card 类型的默认值,My_Card 无须赋值,在声明时已经有了前几个例子中所赋的值。

声明常量记录如下:

My_Card :constant Id_Card := ( Full_Name => "Jack Welch ",
ID_Number => 19830519,
Age => 45,
Birthday => "Jan 1st 1976 ",
Familiy_Address => "China ",
Family_telephone => 8127271;
Job => "CEO ";)

和创建其它类型的常量类似,只需在该记录类型前添个 constant。

变体记录 (Variant Record)

在讲变体记录前,先介绍一下记录判别式(record discriminant)的概念。判别式(discriminant)以前没接触过,这里先简单提一下它的定义:一个复合类型(除了数组)可以拥有判别式,它用来确定该类型的参数(具体参见 RM95 3.7 Discriminant)。也就是说,一个复合类型创建时可以有一些参数,在接下去声明该类型的变量时,可以通过那些参数的值来改变变量初始化时所占用内存大小、成员数量、取值等等。这一节以及下一节的无约束记录(unconstrained record)的内容都在记录判别式的范围内,至于其它复合类型将在以后讲述。

变体记录,即它的一些成员存在与否取决于该记录的参数。如我们将 Id_Card 这个记录类型扩充一下:

type Id_Card (Age : Positive := 1) is
record
Full_Name : String(1..15);
ID_Number : Positive;
Birthday : String(1..15);
Familiy_Address : String(1..15);
Family_telephone : Positive;
Job : String(1..10);
case Age is
when 1 .. 18 => School_Address : String(1..15);
when 19 .. 60 => Monthly_Income : Integer;
Working_Address: String(1..15);

when others => null; -- 如果 Age 的值不属于 1..60,成员不改变

end case;
end record;
My_Card : Id_Card ;
Your_Card: Id_Card (Age => 20);

上例中,case Age ... end case 是变体部份,当 Age 值在 1..18 时,动态创建成员 School_Address;当 Age 值在 19..60 时,动态创建成员 Monthly_Income,Working_Address;当 Age 不在 1..60 时,数据成员不改动。在声明判别式时一般应赋予一个默认值,如上例 Age 的默认值为 1 ,这样声明变量 My_Card 时不带参数也可以,默认参数为 1。但如果 Age 没默认值,上例中的 My_Card 声明是非法的。

因此,记录 My_Card 有 Full_Name,ID_Number,Birthday,Familiy_Address,Family_telephone, Job,School_Address这些成员,因为 Age 默认为 1; 记录 Your_Card 中 Age 值为 20,因此有 Full_Name,ID_Number,Birthday,Familiy_Address,Family_telephone, Job, Monthly_Income,Working_Address 这些成员。

最后注意一下,变体部份要在记录类型声明的底部,不能在 Job 或其他成员前面---变体记录的变量大小是不定的

无约束记录(Unconstrained Record)

上面的记录都是受限定的,如 创建 My_Card 后,它的判别式无法再被改动,Monthly_Income,Working_Address这些成员也无法拥有。但如果 ID_Card 的判别式有了初使值,则还有办法使记录动态改变。

如:

type Id_Card (Age : Positive := 1) is
record
Full_Name : String(1..15);
ID_Number : Positive;
Birthday : String(1..15);
Familiy_Address : String(1..15);
Family_telephone : Positive;
Job : String(1..10);
case Age is
when 1 .. 18 => School_Address : String(1..15);
when 19 .. 60 => Monthly_Income : Integer;
Working_Address: String(1..15);
when others => null;
end case;
end record;

My_Card : Id_Card ;-- 以上和上一节的例子一样

....

begin

...

My_Card := (17, "Jack Welch ", 19830519, "Jan 1st 1976 ", "China ",8127271,

"CEO ","Shanghai ");

end;

赋值的时候就有了点特殊。My_Card 在程序内部赋值,但与常规赋值不同,它的第一个值是判别式的值,后面才是成员的值---成员数量按照判别式的值动态改变,上例就多了一个 School_Address 成员。这种情况下,编译器会分配给 My_Card 可能使用的最大内存空间。因此将下句接在上句后面:

My_Card := (17, "Jack Welch ", 19830519, "Jan 1st 1976 ", "China ",8127271,

"CEO ", 78112 ,"Shanghai ");

也是可行的。

上面一些记录的例子并不好,成员的数据类型太简单(像生日的数据类型,一般是年月日做成员的一个记录),字符串类型太多,手工赋值的话还要数一下有几个字符,实际中也很少这样的用法,一般还是用函数来赋值。这点请注意一下。

判别式的其它用途

判别式的另一个用途是动态决定其成员长度,如:

type Buffer (Size:Integer) is
record
High_Buffer(1..Size);
Low_Buffer(1..Size);
end record;

这样 Buffer 两个成员的大小就取决于 Size 值,在文本处理中这种用法还是挺好的。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号