跳轉到內容

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 問題

[編輯 | 編輯原始碼]
華夏公益教科書