Ada 对象中的常量元素?
Constant element in Ada object?
在 Java 或 C# 中,您通常会有 class 个成员,它们是 final
或 readonly
- 它们被设置一次,然后再也不会被触及。它们可以为 class.
的不同实例保存不同的值
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;
这在声明 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;
您几乎已经有了通用解决方案(对于不能作为判别式的情况)。类型是有限私有的。包的客户端只能通过 pkg 提供的操作来修改它。只要操作不修改有问题的字段,你就有了你想要的(除非我误解了,问题是如何防止你自己修改 pkg 主体中的字段)。
在我回答这个问题之前,区分 Ada 和 Java/C# 的对象建模可能会有所帮助。在 Java 中,一切都是对象,因此所有常量都必须是 final
—— 在 Ada 中,事情有点不同,Ada 的对象系统("tagged types" 在 Ada 的说法中)是建立的基于两个项目:记录和类型推导。这意味着,在教授 OOP 时,我们可以逐步引入类型推导(例如 Type Degree is new Integer;
),然后是记录(即封装),然后是 private
类型(即信息隐藏),最后将所有内容与标记类型统一在一起......我假设你已经意识到了所有这些。
在 Ada 中,constant
就是:一些可以读取但 [通常] 不能写入的对象。 (例如,内存映射 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;
这就是我们如何为标记类型创建常量,同时隐藏其实现细节;不过,诚然,我们本可以公开所有内容并删除整个 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;
现在,在这种情况下,当您执行类似 X : Message := Create("Steve");
的赋值时,变量的类型 [在本例中不受约束,在这种情况下变为 Message(5)
(因为 "Steve"是 5 个字符),因此尝试使用不同大小的消息字符串重新分配是行不通的。 (所以,虽然你不能说 X:= Create("Why")
你 可以 说 X:= Create("Hello")
因为这里的判别式 [Length
] 是 5。) - 所以,以这种方式,判别式在某些情况下可以像常量场一样工作。
limited
关键字表示该类型没有赋值 [但有初始化],因此您 可以 使整个类型表现为常量;这与让一个组件成为 constant
不同,当然不像 T
和 T'Class
之间的区别那么微妙(T'Class
是类型 T
和从那里派生的所有类型,其中 T
是 只有 那个类型。)
在 Java 或 C# 中,您通常会有 class 个成员,它们是 final
或 readonly
- 它们被设置一次,然后再也不会被触及。它们可以为 class.
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;
这在声明 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;
您几乎已经有了通用解决方案(对于不能作为判别式的情况)。类型是有限私有的。包的客户端只能通过 pkg 提供的操作来修改它。只要操作不修改有问题的字段,你就有了你想要的(除非我误解了,问题是如何防止你自己修改 pkg 主体中的字段)。
在我回答这个问题之前,区分 Ada 和 Java/C# 的对象建模可能会有所帮助。在 Java 中,一切都是对象,因此所有常量都必须是 final
—— 在 Ada 中,事情有点不同,Ada 的对象系统("tagged types" 在 Ada 的说法中)是建立的基于两个项目:记录和类型推导。这意味着,在教授 OOP 时,我们可以逐步引入类型推导(例如 Type Degree is new Integer;
),然后是记录(即封装),然后是 private
类型(即信息隐藏),最后将所有内容与标记类型统一在一起......我假设你已经意识到了所有这些。
在 Ada 中,constant
就是:一些可以读取但 [通常] 不能写入的对象。 (例如,内存映射 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;
这就是我们如何为标记类型创建常量,同时隐藏其实现细节;不过,诚然,我们本可以公开所有内容并删除整个 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;
现在,在这种情况下,当您执行类似 X : Message := Create("Steve");
的赋值时,变量的类型 [在本例中不受约束,在这种情况下变为 Message(5)
(因为 "Steve"是 5 个字符),因此尝试使用不同大小的消息字符串重新分配是行不通的。 (所以,虽然你不能说 X:= Create("Why")
你 可以 说 X:= Create("Hello")
因为这里的判别式 [Length
] 是 5。) - 所以,以这种方式,判别式在某些情况下可以像常量场一样工作。
limited
关键字表示该类型没有赋值 [但有初始化],因此您 可以 使整个类型表现为常量;这与让一个组件成为 constant
不同,当然不像 T
和 T'Class
之间的区别那么微妙(T'Class
是类型 T
和从那里派生的所有类型,其中 T
是 只有 那个类型。)