宝书课程#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,因为这将违反受限对象的整个出发点--你不可以复制它们。