跳转到内容

Ada 编程/类型/记录

来自维基教科书,自由的教科书

Ada. Time-tested, safe and secure.
Ada. 经久耐用、安全可靠。


一个记录是一个复合类型,它将一个或多个字段分组在一起。字段可以是任何类型,甚至可以是记录。

基本记录

[编辑 | 编辑源代码]
 type Basic_Record is
    record
       A : Integer;
    end record;

空记录

[编辑 | 编辑源代码]

空记录是指当需要一个没有数据的类型时。有两种方法可以声明一个空记录

type Null_Record is
   record
      null;
   end record; 
type Null_Record is null record;

对于编译器来说,它们是一样的。但是,程序员通常在类型尚未完成时使用第一个变体来表明他们计划稍后扩展该类型,或者他们通常在(带标记的)记录是面向对象编程中的基类时使用第二个变体。

记录值

[编辑 | 编辑源代码]

记录类型的值可以使用记录聚合来指定,给出命名的组件列表,如下所示

  A_Basic_Record       : Basic_Record         := Basic_Record'(A => 42);
  Another_Basic_Record : Basic_Record         := (A => 42);
  Nix                  : constant Null_Record := (null record);

给定一个稍微大一点的记录类型,

  type Car is record
     Identity       : Long_Long_Integer;
     Number_Wheels  : Positive range 1 .. 10;
     Paint          : Color;
     Horse_Power_kW : Float range 0.0 .. 2_000.0;
     Consumption    : Float range 0.0 .. 100.0;
  end record;

可以使用位置表示法来指定一个值,也就是说,按声明顺序为每个记录组件指定一个值

  BMW : Car := (2007_752_83992434, 5, Blue, 190.0, 10.1);

但是,命名一个的组件Car聚合提供了许多优势。

  1. 轻松识别哪个值用于哪个组件。(毕竟,命名组件是记录存在的根本原因。)
  2. 允许重新排序组件——你只需要记住组件名称,而不是它们的位置。
  3. 改进的编译器诊断消息。

可以重新排序组件,因为组件名称将告知编译器(以及人类读者!)预期的值关联。编译器消息的改进也是由于传递给编译器的这些额外信息的结果。虽然由于 Ada 的覆盖规则,省略的组件将始终被报告,但是当存在命名关联时,消息可以更具体。考虑到Car来自上面的类型,假设程序员错误地为两个浮点值中的一个指定了一个值BMW在位置表示法中。编译器在寻找另一个组件值时,将无法确定指定的值是用于Horse_Power_kW还是用于Consumption. 如果程序员使用命名关联,比如 Horse_Power_kW => 190.0,,则将清楚地知道缺少哪个其他组件。

  BMW : Car :=
    (Identity       => 2007_752_83992434,
     Number_Wheels  => 5,
     Horse_Power_kW => 190.0,
     Consumption    => 10.1,
     Paint          => Blue);

为了访问记录实例的组件,请使用点分隔符 (.),例如BMW.Number_Wheels.

带辨别式的记录

[编辑 | 编辑源代码]
 type Discriminated_Record (Size : Natural) is 
    record
       A : String (1 .. Size);
    end record;
 
 ...
 
 Item : Discriminated_Record := (Size => Value'Length, A => Value);

变体记录

[编辑 | 编辑源代码]

变体记录是一种特殊的带辨别式的记录,其中某些组件的存在取决于辨别式的值。

 type Traffic_Light is (Red, Yellow, Green);

 type Variant_Record (Option : Traffic_Light) is 
    record
       -- common components
       
       case Option is
          when Red =>
             -- components for red
          when Yellow =>
             -- components for yellow
          when Green =>
             -- components for green
       end case;
    end record;

可变和不可变变体记录

[编辑 | 编辑源代码]

你可以声明变体记录类型,使其辨别式(以及它的变体结构)可以在变量的生命周期内更改。这样的记录被称为可变的。当“改变”记录时,你必须一次性分配你正在改变的变体结构的所有组件,用完整的变体结构替换记录。虽然变体记录声明可能允许其类型的对象是可变的,但对于对象是否可变有一些限制。限制对象不可变的原因包括

  • 对象是使用辨别式声明的(参见下面的 Immutable_Traffic_Light)
  • 对象是别名的(通过使用aliased 在对象声明中,或通过使用new)


 type Traffic_Light is (Red, Yellow, Green);

 type Mutable_Variant_Record (Option : Traffic_Light := Red) is      -- the discriminant must have a default value
    record
       -- common components
       Location : Natural;
       case Option is
          when Red =>
             -- components for red
             Flashing : Boolean := True;
          when Yellow =>
             -- components for yellow
             Timeout    : Duration := 0.0;
          when Green =>
             -- components for green
             Whatever : Positive := 1;
       end case;
    end record;
...
Mutable_Traffic_Light   : Mutable_Variant_Record;                    -- not declaring a discriminant makes this record mutable
                                                                     -- it has the default discriminant/variant
                                                                     -- structure and values

Immutable_Traffic_Light : Mutable_Variant_Record (Option => Yellow); -- this record is immutable, the discriminant cannot be changed
                                                                     -- even though the type declaration allows for mutable objects
                                                                     -- with different discriminant values
...
Mutable_Traffic_Light   := (Option => Yellow,                        -- mutation requires assignment of all components
                            Location => 54,                          -- for the given variant structure
                            Timeout => 2.3);
...
-- restrictions on objects, causing them to be immutable
type Traffic_Light_Access is access Mutable_Variant_Record;
Any_Traffic_Light       : Traffic_Light_Access :=
                           new Mutable_Variant_Record;
Aliased_Traffic_Light   : aliased Mutable_Variant_Record;


在堆上分配)

 type Traffic_Light is (Red, Yellow, Green);

 type Immutable_Variant_Record (Option : Traffic_Light) is -- no default value makes the record type immutable
    record
       -- common components
       Location : Natural := 0;
       case Option is
          when Red =>
             -- components for red
             Flashing : Boolean := True;
          when Yellow =>
             -- components for yellow
             Timeout    : Duration;
          when Green =>
             -- components for green
             Whatever : Positive := 1;
       end case;
    end record;
...
Default_Traffic_Light   : Immutable_Variant_Record;                    -- ILLEGAL!
Immutable_Traffic_Light : Immutable_Variant_Record (Option => Yellow); -- this record is immutable, since the type declaration is immutable

相反,你可以声明记录类型,使辨别式和变体记录的结构不能更改。要使记录类型声明不可变,辨别式不能具有默认值。

联合

[编辑 | 编辑源代码]

 type Traffic_Light is (Red, Yellow, Green);

 type Union (Option : Traffic_Light := Traffic_Light'First) is 
    record
       -- common components
       
       case Option is
          when Red =>
             -- components for red
          when Yellow =>
             -- components for yellow
          when Green =>
             -- components for green
       end case;
    end record;

 pragma Unchecked_Union (Union);
 pragma Convention (C, Union);    -- optional

此语言功能仅从Ada 2005 开始可用。

与变体记录的区别在于,Option 实际上并不存储在记录中,也不进行正确性检查 - 它只是一个虚拟的。

这种类型的记录通常用于与 C 交互,但也可用于其他目的(然后无需 pragma Convention (C, Union);)。

带标记的记录

[编辑 | 编辑源代码]

type Person is tagged 
   record
      Name   : String (1 .. 10);
      Gender : Gender_Type;
   end record;
type Programmer is new Person with
   record
      Skilled_In : Language_List;
   end record;

带标记的记录是其他语言中称为类的部分。它是Ada 中的面向对象编程 的基础。Ada 中的类还需要另外两个部分,一个是,另一个是基本操作

type Programmer is new Person 
                   and Printable 
with 
   record
      Skilled_In : Language_List;
   end record;

仅限 Ada 2005

抽象带标记的记录

[编辑 | 编辑源代码]

抽象类型至少有一个抽象基本操作,即它的一个操作没有定义,并且实现必须由抽象类型的派生类型提供。

带别名元素

[编辑 | 编辑源代码]如果你来自C/C++,你可能习惯于记录中的每个元素(不是位集的一部分)都有一个地址。在 Ada 中,情况并非如此,因为记录与数组一样可以打包。与数组一样,你可以使用

type Basic_Record is 
   record
      A : aliased Integer;
   end record ;

aliased 来确保可以通过访问类型访问元素。请注意:每个元素都需要它自己的.

aliased

有限记录

[编辑 | 编辑源代码]

除了变体、带标记和抽象之外,记录还可以是有限的(对于有限类型,没有赋值,也没有预定义的相等操作)。在面向对象编程中,当带标记的对象由引用而不是复制来处理时,这与将对象设为有限的很好地融合在一起。

参见

Ada 参考手册

[编辑 | 编辑源代码]

Ada 问题

[编辑 | 编辑源代码]
华夏公益教科书