我刚刚开始使用Ada,我发现通用包声明相当愚蠢。也许我做得不对,所以我正在寻找更好的选择。
看一下下面的例子。
package STD_Code_Maps is new
Ada.Containers.Map(Key_Type => STD_Code_Type;
Element_Type => Ada.Strings.Unbounded.Unbounded_String);
STD_Code_Map : STD_Code_Maps.Map;
-- . . .
procedure Do_Something is
Item : Ada.Strings.Unbounded.Unbounded_String;
begin
Item := STD_Code_Maps.Element(STD_Code_Maps.First(STD_Code_Map));
-- Do something with the Item
-- . . .
end Do_Something;
简单地写STD_Code_Map.First.Element
代替被遗忘的STD_Code_Maps.Element(STD_Code_Maps.First(STD_Code_Map));
显然我做错了 - 我想。我在那里至少重复三次STD_Code_Map这个短语。我只是为了冗长和一切,但实际上我写的代码对我来说似乎很糟糕和愚蠢。
我想知道是否有解决方案没有要求您将包重命名为package Map renames STD_Code_Maps;
,这当然会缩短代码但我不想这样做这在每个程序条目上都有。我真的认为STD_Code_Map.First.Element
这样的东西会简单得多。这可以在Ada 2012中完成吗?
注意:默认情况下使用Unbounded_String包也很困难。标准库设计者是否真的考虑过荒谬且过长的包层次结构?
感谢您阅读本文,并可能帮助我。我是阿达的新手。
答案 0 :(得分:5)
GNAT GPL 2012和2013,以及FSF GCC 4.7和4.8,支持Ada 2012的新容器索引方案,这意味着您可以编写
Item := STD_Code_Map ({some Cursor});
即使使用-gnat05
开关强制执行Ada 2005模式,您也可以这样做! (这必须是一个错误)。
Ada 2005允许您使用object.function
表示法调用标记类型的原始函数,前提是第一个操作数是标记类型;因此,您可以将STD_Code_Map.First
写为STD_Code_Maps.First (STD_Code_Map)
的简写。
将这些放在一起,你可以写
Item := STD_Code_Map (STD_Code_Map.First);
这很短!
答案 1 :(得分:4)
这个问题与泛型无关。正如Simon指出的,你可以说STD_Code_Map.First,因为STD_Code_Map的类型是标记类型,而Ada支持标记类型的这种表示法。另一方面,STD_Code_Map.First的类型是Cursor类型,它没有被标记(使得它被标记会导致声明某些同时采用Cursor和Map的操作的问题)。但即使没有Simon提到的Ada 2012容器索引,你也可以说
STD_Code_Maps.Element(STD_Code_Map.First);
哪个好一点。除了重命名包之外,您还可以重命名该功能:
function Elem (Position : STD_Code_Maps.Cursor) return STD_Code_Maps.Element_Type
renames STD_Code_Maps.Element;
现在,只要重命名直接可见,您就可以使用Elem
代替STD_Code_Maps.Element
。 (如果需要,可以将其称为Element
。重命名名称可以相同,也可以不同。)如果您经常使用该功能,这可能会有所帮助。
答案 2 :(得分:3)
Ada旨在提高可读性和可维护性。 (一次写入,读取和保持更长时间)这意味着它有时会变得有点冗长。如果你更喜欢简洁和放松神秘的还有很多其他语言!
如果您想避免一直输入STD_Code_Map,只需使用use
子句:
use STD_Code_Map;
这意味着你的代码
Item := STD_Code_Maps.Element(STD_Code_Maps.First(STD_Code_Map));
会变成
Item := Element(First(STD_Code_Map));
答案 3 :(得分:2)
让Ada中的名字变得美观可读有时会很棘手。通常情况下,语言设计师通过设计Ada标准库包以便与Ada use
条款一起使用来使任务变得更糟糕,而没有考虑他们如何看待一些不能或者不想使用该功能。
在这种情况下,你可以自己做一些事情。
例如“_Maps.Map”是多余的,那么为什么不从包名中删除它呢?为什么不使用名称,以便您可以写:
package STD_Code is new
Ada.Containers.Map(Key_Type => STD_Code_Type;
Element_Type => Ada.Strings.Unbounded.Unbounded_String);
Map : STD_Code.Map;
-- . . .
procedure Do_Something is
Item : Ada.Strings.Unbounded.Unbounded_String;
begin
Item := STD_Code.Element(STD_Code.First(Map));
-- Do something with the Item
-- . . .
end Do_Something;
现在Code
看起来像是一个空意义词。程序中的 Everything 是一个代码。所以我也考虑放弃它。不合理地,我将我的Ada容器包命名为其基本理论功能(例如:STD_to_String
),而对象则是更具体的名词。
另外,我应该指出,如果您的地图是常量并且您可以使用看起来像标识符的名称,通常可以使用枚举类型和'image
属性完全删除地图到字符串
答案 4 :(得分:0)
如果您使用的是Ada 2012,STD_Code_Maps.Element(STD_Code_Maps.First(STD_Code_Map));
可能会成为:
Function Get_First( Map : STD_Code_Maps.Map ) return Unbounded_String is
( STD_Code_Maps.Element(Map.First) );
这是一个新的表达式函数的例子,它主要是针对前后条件引入的。
当然,如果您使用的是Ada 2012,那么您可能想要的精确地图是Ada.Containers.Indefinite_Ordered_Maps
- Indefinite_ *容器是[可]具有不确定元素的容器,例如String
除了TED的评论之外,当映射是常量时使用枚举还有更多优点,即案例覆盖:编译器会将任何不包含所有备选方案的case语句标记为错误。因此,如果添加新代码,它将标记您需要修改的所有case语句。 (当然,当您使用others
案例时,这种好处就会丢失。)