0

我刚刚开始使用 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 包也很困难。标准库设计者是否真的对荒谬和过长的包层次结构给予了很多考虑?

感谢您阅读本文,并可能帮助我。我是艾达的新手。

4

5 回答 5

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);

这很短!

于 2013-08-16T12:48:02.147 回答
4

The issue has nothing to do with generics. As Simon pointed out, you can say STD_Code_Map.First, since the type of STD_Code_Map is a tagged type and Ada supports this notation for tagged types. On the other hand, the type of STD_Code_Map.First is a Cursor type, which isn't tagged (making it tagged would have caused problems declaring certain operations that take both a Cursor and a Map). But even without the Ada 2012 container indexing that Simon mentioned, you can say

STD_Code_Maps.Element(STD_Code_Map.First);

which is a little better. Besides renaming a package, you can also rename the function:

function Elem (Position : STD_Code_Maps.Cursor) return STD_Code_Maps.Element_Type
    renames STD_Code_Maps.Element;

and you can now use just Elem instead of STD_Code_Maps.Element wherever the renaming is directly visible. (You could call it Element if you want to. The renaming name can be the same or it can be different.) This could be helpful if you use that function a lot.

于 2013-08-16T16:05:01.663 回答
3

在 Ada 中获得好听且易读的名称有时会很棘手。通常,语言设计者通过设计与 Adause子句一起使用的 Ada 标准库包来使任务变得更糟,而不考虑他们会如何看待一些不能或不想这样做的可怜的 sap使用该功能。

但是,在这种情况下,您可以自己做一些事情。

例如“_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看起来也有点像一个空意义的词。程序中的一切都是代码。所以我也会考虑放弃它。不寻常的是,我将我的 Ada 容器包装命名为说明其基本理论功能的东西(例如:)STD_to_String,而对象是更具体的名词。

另外,我应该指出,如果您的映射是常量并且您可以使用看起来像标识符的名称,通常您可以通过使用枚举类型和'image属性来完全摆脱映射到字符串。

于 2013-08-16T18:53:33.813 回答
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));
于 2013-08-16T08:26:14.703 回答
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 的评论之外,在映射不变时使用枚举还有更多优势,即案例覆盖:编译器会将任何不涵盖所有替代方案的案例语句标记为错误。因此,如果您添加新代码,它将标记您需要修改的所有案例陈述。(当然,当你使用这个others案例时,这个好处就消失了。)

于 2013-08-17T05:35:29.870 回答