寶書課程#1:Ada 2005中的受限型別 --受限集合
寶書課程#1:Ada 2005中的受限型別
--受限集合
by Bob Duff—AdaCore
Translator:Dongfeng.Gu
讓我們開始吧…
一個Ada我所喜歡的特徵是對於集合的“全覆蓋規則”。例如,假設我們有一個記錄型別:
type Person is
record
Name : Unbounded_String;
Age : Years;
end record;
我們可以使用一個集合來建立一個這個型別的物件:
X : constant Person :=
(Name => To_Unbounded_String (”John Doe”),
Age => 25);
全覆蓋規則意思是所有的Person的成員必須在集合中記錄。如果我們接著通過增加一個成員來修改Person型別:
type Person is
record
Name : Unbounded_String;
Age : Natural;
Shoe_Size : Positive;
end record;
我們忘記修改X,於是編譯器將提醒我們。Case語句也同樣有全覆蓋規則,它提供一個近似的目的。
當然,我們可以通過使用“others”來擊敗全覆蓋規則(通常用於陣列集合與情形語句,也偶爾對記錄集合有用):
X : constant Person :=
(Name => To_Unbounded_String (”John Doe”),
others => 25);
根據Ada參考手冊,“others”這裡精確的表示“Age|Shoe_Size”。但那是錯誤的:“others”真實的含義是“其它所有成員,包含我們可能在下週或下年將新增的成員”。這意味著你不應該使用“others”,除非你非常確信它將適用於所有未創作的情形。
到目前為止,這都是舊新聞了--自從Ada83以來全覆蓋規則一直被維護。這和Ada2005有什麼關係呢?
假設我們有一個受限型別:
type Limited_Person is limited
record
Self : Limited_Person_Access := Limited_Person'Unchecked_Access;
Name : Unbounded_String;
Age : Natural;
Shoe_Size : Positive;
end record;
這個型別有一個自引用,它對複製物件沒有意義,因為Self將最後指向錯誤的地方。因此,我們希望使型別受限,來防止程式設計師意外地建立副本。總之,該型別可能是私有的,因此客戶端程式設計師可能不會意識到這個問題。我們也可以通過受控型別來解決那個問題,但是受控型別是費開銷的,並且會增加不必要的複雜度,如果沒有必要的話,就不要使用受控型別。
在Ada95中,對於受限型別的集合(宣告)是非法的。因此,我們將面臨一個艱難的選擇:建立受限型別物件,並且像這樣初始化它:
X : Limited_Person;
X.Name := To_Unbounded_String ("John Doe");
X.Age := 25;
這裡有一個全覆蓋規則應該防止的維護問題。或許,使型別非受限,這樣可以獲得集合(宣告)的福利,但卻失去防止拷貝的能力。
在Ada2005中,一個集合(宣告)可以用於受限物件。我們可以說:
X : aliased Limited_Person :=
(Self => null, – Wrong!
Name => To_Unbounded_String (”John Doe”),
Age => 25,
Shoe_Size => 10);
X.Self := X'Access;
我們將在未來的寶書課程中看到“Self=>null”做了什麼。
一個非常重要的要求需要指出:建立X的值必須現場實現,不可以在一個臨時變數中建立一個集合宣告,然後複製它到X,因為這將違反受限物件的整個出發點--你不可以複製它們。