跳轉到內容

Ada 程式設計/型別/受限

來自華夏公益教科書,開放書籍,開放世界

Ada. Time-tested, safe and secure.
Ada.經受時間考驗,安全可靠。

受限型別

[編輯 | 編輯原始碼]

當一個型別被宣告為limited 這意味著該型別的物件不能被賦值為相同型別的其他物件。一個物件b屬於受限型別LT不能被複制到一個物件a屬於相同型別。LT.

此外,對於受限型別的物件沒有預定義的相等操作。

宣告一個受限型別的預期效果包括防止淺複製。此外,物件的(唯一)標識將被保留:一旦宣告,變數的名稱將繼續引用同一個物件。LT以下示例將使用一個相當簡單的型別

Boat當我們將一個變數宣告為型別.

     type Boat is limited private;

     function Choose
       (Load  : Sailors_Units;
        Speed : Sailors_Units)
        return  Boat;

     procedure Set_Sail (The_Boat : in out Boat);

時,它的名稱將從那時起表示一條船。船隻不會相互複製。當我們將一個變數宣告為型別船的完整檢視可能被實現為一個記錄,例如

     type Boat is limited record
        Max_Sail_Area : Sailors_Units;
        Max_Freight   : Sailors_Units;
        Sail_Area     : Sailors_Units;
        Freight       : Sailors_Units;
     end record;

Choose函式返回一個物件,具體取決於引數當我們將一個變數宣告為型別LoadSpeed。如果我們現在宣告一個型別為 Boat 的變數,我們最好選擇一個初始的 Boat(否則我們可能會掉入未初始化的水域!)。但是當我們這樣做時,初始化看起來很像賦值,而賦值在受限型別中是不可用的幸運的是,當前的 Ada 區分初始化和複製。受限型別的物件可以透過初始化表示式在分隔符 := 右側進行初始化。

  procedure Travel (People : Positive; Average_Speed : Sailors_Units) is

     Henrietta : Boat :=   -- assignment?
        Choose
          (Load  => People * Average_Weight * 1.5,
           Speed => Average_Speed * 1.5);

  begin
     Set_Sail (Henrietta);
  end Travel;

(為了避免混淆:Ada 參考手冊區分了賦值賦值語句,其中賦值是賦值語句的一部分。初始化當然是一種賦值,對於受限型別,它是在原地完成的。賦值語句涉及複製,而複製對於受限型別是禁止的。)

與該特性相關的是 受限型別的聚合體 和受限型別的“建構函式”。在內部,

函式將返回一個受限記錄。但是,由於返回型別函式返回一個是受限的,因此任何地方都不允許複製。這會起作用嗎?第一次嘗試可能是宣告一個當我們將一個變數宣告為型別result變數區域性於,操作函式返回一個,並返回它。該變數區域性於物件需要“傳輸”到呼叫環境。但是變數區域性於是一個區域性於變數區域性於的變數。當函式返回一個返回時,函式返回一個將不再在範圍內。因此看起來變數區域性於必須被複制,但這對於受限型別是不允許的。語言提供了兩種解決方案:擴充套件返回語句(參見 6.5:返回語句 [註釋])和受限型別的聚合體。以下變數區域性於的函式體函式返回一個返回一個受限型別當我們將一個變數宣告為型別的聚合體,在找到其元件的初始值後。

     function Choose
       (Load  : Sailors_Units;
        Speed : Sailors_Units)
        return  Boat
     is
        Capacity : constant Sailors_Units := Capacity_Needed (Load);
     begin
        return Boat'
          (Max_Freight   => Capacity,
           Max_Sail_Area => Sail_Needed (Capacity),
           Freight       => Load,
           Sail_Area     => 0.0);
     end Choose;

返回的物件同時也是要賦予返回值的物件。因此,該函式在Henrietta 中初始化.

。與預定義型別 Ada.Finalization.Controlled類似,Ada 提供了型別Limited_Controlled在同一個包中。它是前者的受限版本。

初始化受限型別

[編輯 | 編輯原始碼]

介紹了幾種初始化此類型別的方法。

package Limited_Private_Samples is

  type Uninitialised  is limited private;
  type Preinitialised is limited private;

  type Dynamic_Initialisation is limited private;
  function Constructor (X: Integer)  -- any kind of parameters
    return Dynamic_Initialisation;

  type Needs_Constructor (<>) is limited private;
  function Constructor (X: Integer)  -- any kind of parameters
    return Needs_Constructor;

private

  type Uninitialised is record
    I: Integer;
  end record;

  type Preinitialised is record
    I: Integer := 0;  -- can also be a function call
  end record;

  type Void is null record;
  function Constructor (Object: access Dynamic_Initialisation) return Void;

  type Dynamic_Initialisation is limited record
    Hook: Void := Constructor (Dynamic_Initialisation'Access);
    Bla : Integer;  -- any needed components
  end record;

  type Needs_Constructor is record
    I: Integer;
  end record;

end Limited_Private_Samples;
package body Limited_Private_Samples is

  function Constructor (Object: access Dynamic_Initialisation) return Void is
  begin
    Object.Bla := 5;  -- may be any value only known at run time
    return (null record);
  end Constructor;

  function Constructor (X: Integer) return Dynamic_Initialisation is
  begin
    return (Hook => (null record),
            Bla  => 42);
  end Constructor;

  function Constructor (X: Integer) return Needs_Constructor is
  begin
    return (I => 42);
  end Constructor;

end Limited_Private_Samples;
 with Limited_Private_Samples;
 use  Limited_Private_Samples;
 
 procedure Try is
 
   U: Uninitialised;   -- very bad
   P: Preinitialised;  -- has initial value (good)
  
   D1: Dynamic_Initialisation;  -- has initial value (good)
   D2: Dynamic_Initialisation := Constructor (0);  -- Ada 2005 initialisation
   D3: Dynamic_Initialisation renames Constructor (0);  -- already Ada 95
 
   -- I: Needs_Constructor;  -- Illegal without initialisation
   N: Needs_Constructor := Constructor (0);  -- Ada 2005 initialisation
 
 begin
 
   null;
 
 end Try;

請注意,D3 是一個常量,而其他所有都是變數。

還要注意,為 Preinitialised 的元件定義的初始值是在物件建立時評估的,即,如果使用表示式而不是字面量,則該值可以依賴於執行時。

X, Y: Preinitialised;

在兩個物件的這個宣告中,初始表示式將被評估兩次,並且可以提供不同的值,因為它等效於以下序列:[1]

X: Preinitialised;
Y: Preinitialised;

所以 X 在 Y 之前初始化。

Ada 95 參考手冊

[編輯 | 編輯原始碼]

Ada 2005 參考手冊

[編輯 | 編輯原始碼]

Ada 質量和風格指南

[編輯 | 編輯原始碼]

參考資料

[編輯 | 編輯原始碼]
  1. ISO/IEC 8652:2007. "3.3.1 物件宣告 (7)". Ada 2005 參考手冊. 任何包含 [...] 多個 defining_identifier 的宣告 [...] 等效於一系列宣告,每個宣告包含列表中的一個 defining_identifier,[...] 順序與列表相同。 {{cite book}}: Unknown parameter |chapterurl= ignored (|chapter-url= suggested) (help)
華夏公益教科書