提供对变量的只读访问权限(当然?)可以通过抽象实现。例如,我可以将变量设置为可调用实体或泛型的 in 模式参数。然后,变量的使用(通过这些常量视图)将被限制在可调用或通用实例中。
这个结构不容易添加到现有程序中,我认为,因为该程序已经结构化;此外,它不是一个独立的解决方案,因为它需要在“只读”和结构之间进行耦合。
另一个选择是使变量为private并导出一个返回其值的函数。但是,我想要直接曝光,例如 volatile 常量,从不同的角度来看仍然是一个变量。
我想出了一个叠加层:
with Interfaces;
package Read_Only is
subtype Pins is Interfaces.Unsigned_16;
V : constant Pins with Volatile, Import;
private
Backing : Pins with Volatile;
for V'Address use Backing'Address;
procedure Reset;
end Read_Only;
这会屏蔽V
,以便只有包体(和子)可以修改其值,而包的客户端可以读取V
。但是“隐藏”所有这些背后的方面和地址让我想到:还有其他一些更明显的方法吗?
修改:通过@ flyx的评论提醒,该软件包的公开部分的读者会看到constant
并且可能认为V
在物理上是恒定的 - 它是不是,volatile
。我更希望能够保留两者 V
的类似对象字符以及无法从外部Read_Only
更改的事实。 V
这里实际上并不是一个常量对象,但它的声明是这样说的。我想我想声明一个可识别的易变物体或一些物体的恒定视图,而不会产生函数的偶然性。
答案 0 :(得分:3)
我的建议是,使用一个简单的函数和一个私有变量:
with Interfaces;
package Read_Only is
subtype Pins is Interfaces.Unsigned_16;
function V return Pins;
private
Backing : Pins;
function V return Pins is (Backing);
end Read_Only;
Ada的调用约定将确保以最有效的方式返回对象。
此外,将其实现为表达式函数将确保调用内联。如果您希望直接曝光并且在任何情况下都不需要调用,即使您在没有优化的情况下进行编译,也可以使用Inline_Always方面:
function V return Pins with Inline_Always;
在这种情况下,调用始终内联到访问的变量,因此就发出的代码而言,它完全等同于直接访问。
编辑:对不起,我刚看到你不想要一个功能。鉴于上述情况,我不明白为什么会这样。你能给出一个更准确的理由吗?答案 1 :(得分:1)
有趣的问题。
提供对变量的只读访问权限(当然?)可以通过抽象实现。例如,我可以将变量设置为可调用实体或通用实体的模式参数。然后,变量的使用(通过这些常量视图)将被限制在可调用或通用实例中。
这个结构不容易添加到现有程序中,我认为,因为该程序已经结构化;此外,它不是一个独立的解决方案,因为它需要在“只读”和结构之间进行耦合。
我不确定仿制药会有多难,但如果您愿意重新考虑仿制药的使用,我认为您可以这样做:
Generic
Type Alpha(<>) is private;
Package Constant_Access is
Type Beta is access constant Alpha;
Subtype Gamma is not null Beta;
Generic
Item_Access : in Gamma;
Package Access_Accessor is
Item : Constant Alpha renames Item_Access.all;
Pragma Volatile( Item );
End Access_Accessor;
End Constant_Access;
然后,当您需要提供一个仅限常量的视图时,在特定类型的Access_Accessor
实例化上使用Constant_Access
实例化 - 然后,在该实例化之后立即重命名实例化Item
到要隐藏/保持不变的值的名称。
是的,这有点尴尬,但它确实确保你想要的属性(即,可能是不稳定的),即使面对大量的优化。
<强>编辑:强>
With
System.Address_To_Access_Conversions;
Generic
Type Alpha(<>) is private;
Package Constant_Access with Preelaborate is
Package Conversions is new System.Address_To_Access_Conversions( Alpha );
Use Conversions, System;
-----------------------
-- Type Declarations --
-----------------------
Type Beta is access constant Alpha;
Subtype Gamma is not null Beta;
Type Epsilon( G : Not Null Access Constant Alpha ) is null record
with Implicit_Dereference => G, Volatile;
-- NOTE: You could excise Beta and Gamma, they are included for flexibility.
--------------------------
-- Conversion Functions --
--------------------------
Function "+"( Right : Aliased Alpha ) return Gamma is
( Right'Access );
Function "+"( Right : Gamma ) return Alpha is
( Right.All );
Function "+"( Right : Gamma ) return Epsilon is
( G => Right.All'Access );
Function "+"( Right : Epsilon ) return Gamma is
( Right.G );
Function "+"( Right : Aliased Alpha ) return Epsilon is
( G => Right'Access );
Function "+"( Right : Epsilon ) return Alpha is
( Right.G.All ); -- Not actually needed due to implicit dereferencing.
Function "+"( Right : Not Null Access Constant Alpha ) return Address is
( Right.All'Address );
Function "+"( Right : Address ) return Alpha is
( To_Pointer(Right).All );
Function "+"( Right : Epsilon ) return Address is
( +Right.G );
Function "+"( Right : Address ) return Epsilon is
( G => +To_Pointer(Right).All );
-----------------------
-- Accessor Generics --
-----------------------
Generic
Item_Access : in Gamma;
Package Access_Accessor is
Item : Epsilon( Item_Access )
with Volatile;
End Access_Accessor;
Generic
Item_Address : in System.Address;
Package Address_Accessor is
Item : Epsilon := +Item_Address
with Volatile;
End Address_Accessor;
End Constant_Access;