在Java或C#中,通常会有类成员final或readonly- 它们被设置一次然后再也不会被触及.它们可以为类的不同实例保存不同的值.
Ada有类似的东西吗?我试图在Ada中创建类似的东西:
package MyPackage is
type MyObject is limited new OtherPackage.Object with private;
....
private
type MyObject (...) is limited new OtherPackage.Object with
record
M_MyField : Integer := 10;
M_MyConstantFactory : constant Factory.Object'Class := new Factory.Object;
end record;
end MyPackage;
Run Code Online (Sandbox Code Playgroud)
这声明的M_MyConstantFactory说法失败了constant components are not permitted.有没有解决的办法?一位同事建议在包中的其他地方声明它,但这意味着M_MyConstantFactory在所有实例中共享一个,这不是我想要的.
我是否需要接受一旦设置就可以修改该值并手动防止发生这种情况?
不,不是.
如果您的组件是离散类型或访问类型,则可以使其成为判别式,从而使其成为不可变的.
with Ada.Integer_Text_IO;
procedure Immutable_Components is
type Instance (Immutable : Positive) is null record;
A : Instance := (Immutable => 1);
begin
Ada.Integer_Text_IO.Put (A.Immutable);
-- A.Immutable := 2; -- assignment to discriminant not allowed:
end Immutable_Components;
Run Code Online (Sandbox Code Playgroud)
在回答这个问题之前,区分 Ada 和 Java/C# 的对象建模可能会有所帮助。在 Java 中,一切都是对象,因此所有常量都必须是final——在 Ada 中,情况有点不同,Ada 的对象系统(Ada 术语中的“标记类型”)建立在两项之上:记录和类型派生。这意味着,在教授OOP时,我们可以逐步引入首先类型派生(例如Type Degree is new Integer;),然后是记录(即封装),然后private是类型(即信息隐藏),最后将所有内容与标记类型统一在一起......所有这些我假设你都知道。
在 Ada 中,aconstant就是:一些可以读取但[通常]不能写入的对象。(例如内存映射 IO,事情会变得很有趣。)所以我们可以说:
Package Ex1 is
Type Stub1 is private; -- Some type, with almost nothing public.
C1 : Constant Stub1; -- A constant of that type.
Private
Type Stub1 is tagged record
Data_1 : Integer;
Data_2 : Float;
end;
-- And now we can tell the compiler what C1 _is_.
C1: Constant Stub1 := (Data_1 => 3, Data_2 => 1.2);
End Ex1;
Run Code Online (Sandbox Code Playgroud)
这就是我们如何为标记类型创建常量,同时隐藏其实现细节;不过,不可否认的是,我们可以暴露所有内容并删除整个private部分。
现在我们了解记录[和标记类型]的一个有趣的功能,称为判别式——它们有点像常量,也有点像其他语言中的泛型类型。通过判别式,我们可以根据消息长度创建大小不同的消息类型:
Package Ex2 is
Type Message(Length : Natural) is private; -- A message.
Function Create( Text : String ) return Message;
Private
Type Message(Length : Natural) is record
Data : String(1..Length) := (Others => ' '); -- Defaults to space-filled string.
end;
Function Create( Text : String ) return Message is
( Data => Text, Length => Text'Length );
End Ex2;
Run Code Online (Sandbox Code Playgroud)
现在,在这种情况下,当您执行类似变量类型的分配时X : Message := Create("Steve");[不受约束,在本例中,在这种情况下会受到约束Message(5)(因为“Steve”是 5 个字符),因此尝试使用不同大小的消息重新分配- 字符串不起作用。(所以,虽然你不能说X:= Create("Why")你可以说X:= Create("Hello"),因为这里的判别式 [ Length] 是 5。) - 所以,以这种方式判别式在某些情况下可以像常数场一样。
该limited关键字意味着该类型没有赋值[但有初始化],因此您可以使整个类型表现为常量;这与使用一个组件不同constant,当然不像Tand之间的区别那么微妙T'Class(T'Class是 TypeT和从其派生的所有类型,其中 as仅T是该类型。)