ADA 95教程 高级特性 高级数组主题

 

Example program ------> e_c19_p1.ada

-- Chapter 19 - Program 1
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

procedure Summer is

   type MY_ARRAY is array (POSITIVE range <>) of INTEGER;

   Dummy1 : constant MY_ARRAY := (27, 14, 13, 33);
   Dummy2 : constant MY_ARRAY := (112 => 27, 113 => 14,
                                  114 => 13, 115 => 33);

   My_List : MY_ARRAY(1..12);
   Stuff   : MY_ARRAY(4..11) := (12, 13, 7, 11, 125, others => 17);
   Total   : INTEGER;

      function Sum_Up(In_Array : MY_ARRAY) return INTEGER is
      Sum : INTEGER := 0;
      begin
         for Index in In_Array'FIRST..In_Array'LAST loop
            Sum := Sum + In_Array(Index);
         end loop;
         Put("The sum of the numbers is");
         Put(Sum, 4);
         New_Line;
         return Sum;
      end Sum_Up;

begin
   My_List := (0, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 7);
   Stuff := (4 => 12, 8 => 11, 5 => 13, 7 => 1, others => 9);

   Total := Sum_Up(My_List);
   Total := Sum_Up(Stuff);
end Summer;




-- Result of Execution

-- The sum of the numbers is  32
-- The sum of the numbers is  73

检查名为e_c19_p1.ada的文件,以获取第7行中所示的无约束数组类型的示例。框(<>),正如它所说的,指的是以后必须填写的内容,并且是一个将在Ada的许多其他地方使用的构造。请注意,第7行中的索引类型是POSITIVE,这一事实将对其以后的使用产生影响。

 

无约束数组类型的使用

在第9行中,我们声明了一个MY_ARRAY类型的数组常量,并使用位置聚合为这些常量赋值。由于我们没有给出数组的索引范围,系统将分配它们,在这种情况下,将使用范围1到4,因为索引类型使用类型POSITIVE 。如果我们将使用INTEGER类型作为索引,那么所选的范围将是-2147483648到-2147483645,这是整数范围的下限,除非您的实现对INTEGER使用了不同的下限。仔细选择数组索引类型非常重要。在第10行中,我们声明了另一个常量数组,但是这次我们使用了一个命名聚合,系统没有机会选择范围,我们自己显式地选择它。索引不必像这里那样按连续顺序命名,但必须给出所有值。

我们在第13行声明了一个未初始化的变量数组(范围从1到12),在第14行声明了一个初始化的变量数组,它使用了初始化的位置聚合方法。others 部分将用值17填充位置9、10和11。数组聚合中使用的others 构造是ada95中的新构造。它只能与受约束的数组一起使用,并且必须是列表中的最后一个数组。

 

非常灵活的功能

第17行到第27行中的函数似乎对其形式参数变量使用了一个无约束数组,确实如此,但每次使用函数时,形式参数数组都被约束到实际变量的极限。在程序的第33行中调用函数时,使用My_List作为实际数组变量,My_List的范围1到12用于函数中形式参数的范围。这样就可以按所示的方式在函数中使用数组属性,使它们依赖于实际参数使用的数组。当Stuff用于实际参数时,函数中的形式参数的范围为4到11。因此,函数的编写方式可以使其具有内置的灵活性,即使继续进行强类型检查,因为如果在本示例程序中有一个无约束类型,则函数不能与另一个无约束类型一起使用。请注意,所有的数组属性在这里都可用,就像它们在任何数组中一样。

 

关于这种类型的一些注释

MY_ARRAY类型的每个变量的所有元素都将是INTEGER类型,所有索引都将是包括范围限制在内的subtype POSITIVE。名为My_List和Stuff的变量属于同一类型,具有不同的限制,因此切片可以与它们一起使用。研究完这个程序后,编译并执行它,这样就可以观察输出了。

 

具有枚举索引的数组

Example program ------> e_c19_p2.ada

-- Chapter 19 - Program 2
with Ada.Text_IO, Ada. Float_Text_IO;
use Ada.Text_IO, Ada.Float_Text_IO;

procedure EnumAry is

   type DAY is (MON, TUE, WED, THU, FRI, SAT, SUN);

   Hours       : array(DAY) of FLOAT;
   Total_Hours : FLOAT;
   Today       : DAY;

begin
   for Today in MON..FRI loop
      Hours(Today) := 8.0;
   end loop;

   Hours(SAT) := 4.0;
   Hours(SUN) := 0.0;

   Total_Hours := 0.0;
   for Today in DAY loop
      Total_Hours := Total_Hours + Hours(Today);
   end loop;

   Put("Total hours for the week =");
   Put(Total_Hours, 5, 2, 0);
   New_Line;

end EnumAry;




-- Result of Execution

-- Total hours for the week =   44.00

检查名为e_c19_p2.ada的程序,以获取一个数组的示例,该数组带有索引的枚举变量。由于数组的索引可以是任何离散类型,并且枚举类型是离散的,因此根据Ada标准,它可以用于数组索引。

我们定义一个名为DAY的枚举类型,该类型将一周中的几天作为元素,然后使用类型DAY声明一个数组作为索引。显然,这是一种匿名数组类型,在重要的程序中不鼓励使用这种类型,但在像这样的简单程序中不应导致类型转换问题。最后,我们声明另外两个简单变量供以后使用,并开始程序的可执行部分。

我们使用一个循环,从周一到周五为每天分配8.0小时,然后为周六分配4.0小时,为周日分配0.0小时。最后,我们总结了一周的小时数,并将其显示在显示器上。这是一个非常简单的程序,但它说明了Ada中一个非常有用的构造。因此,你应该花足够的时间研究它,直到你彻底理解它。一定要编译并执行e_c19_p2.ada.

 

数组运算符

Example program ------> e_c19_p3.ada

 -- Chapter 19 - Program 3
with Ada.Text_IO;
use Ada.Text_IO;

procedure ArrayOps is

   type ARY_INT is array(1..6) of INTEGER;
   type ARY_BOOL is array(4..7) of BOOLEAN;

   Do_They_Compare          : BOOLEAN;
   Crowd, Group1, Group2    : ARY_INT;
   Result, Answer1, Answer2 : ARY_BOOL;

begin

   Group1 := (12, 17, -1, 3, -100, 5);
   Group2 := (13, -2, 22, 1, 1242, -12);

   Do_They_Compare := Group1 <= Group2;
   Do_They_Compare := Group1 > Group2;

   if Group1 = Group2 then
      Put("The arrays are equal."); New_Line;
   end if;

-- Crowd := Group1 + Group2;
-- Crowd := Group1 - Group2;
-- Crowd := Group1 * Group2;
-- Crowd := Group1 / Group2;
-- Crowd := Group1 mod Group2;
-- Crowd := Group1 rem Group2;

   Answer1 := (TRUE, FALSE, TRUE, FALSE);
   Answer2 := (TRUE, FALSE, FALSE, TRUE);

   Result := Answer1 and Answer2;
   Result := not Answer2;
   Result := Answer1 or Answer2;
   Result := Answer1 xor Answer2;

   if Answer1 /= Answer2 then
      Put("The BOOLEAN arrays are not equal."); 
      New_Line;
   end if;

end ArrayOps;




-- Result of execution

-- The BOOLEAN arrays are not equal.

 

本教程前面讨论的一些操作符可用于数组。它们对数组的每个元素进行操作,就像在循环中进行操作一样。示例程序e_c19_p3.ada将演示其中一些操作的使用。

第19行到第24行说明了用于整个数组的逻辑运算符。数组逐元素进行比较,一旦在两个对应的元素中发现差异,这两个元素的比较结果将作为整体比较结果返回。如果所有相应的元素相等,则比较的结果相等。

请注意,使用记录数组是合法的,有时非常有用。可以比较记录数组的相等或不相等,但不能比较其他四个运算符(>、>=、<、<=),因为它们与单个记录元素一起使用是非法的。如果我们不明确说明,你的一些想法就会得出这个结论。使用Ada可以实现许多这样的操作组合。这将取决于你自己尝试一些,因为你需要他们,因为有太多的排列,我们来描绘所有的。

 

算术数组运算符

第26行到第31行中注释中所示的运算符不可作为Ada的一部分使用,但可以通过使用运算符重载使它们对程序可用。这将在下一个示例程序中说明。

 

布尔数组运算符

使用第33行和第34行中的位置聚合为两个布尔数组赋值,然后在第36行到第44行中用作完整数组。逻辑运算符的使用方式与此文件中先前使用的比较运算符基本相同。请注意,这些运算符生成另一个数组,每个元素都是比较数组中相应元素的逻辑运算的结果。比较运算符可用于布尔数组,其方式与其他标量数组类似,只返回一个布尔类型的结果值。在你理解了新材料之后,编译并运行这个程序。

 

如何编写算术数组运算符

Example program ------> e_c19_p4.ada

                                       -- Chapter 19 - Program 4
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

procedure ArrayOp2 is

   type ARY_INT is array(1..6) of INTEGER;

   Crowd, Group1, Group2    : ARY_INT;

   function "+"(In_Array1, In_Array2 : ARY_INT) return ARY_INT is
   Temp_Array : ARY_INT;
   begin
      for Index in ARY_INT'RANGE loop
         Temp_Array(Index) := In_Array1(Index) + In_Array2(Index);
      end loop;
      return Temp_Array;
   end "+";

   function "mod"(In_Array1, In_Array2 : ARY_INT) return ARY_INT is
   Temp_Array : ARY_INT;
   begin
      for Index in ARY_INT'RANGE loop
         Temp_Array(Index) := In_Array1(Index) mod In_Array2(Index);
      end loop;
      return Temp_Array;
   end "mod";

begin

   Group1 := (12, 17, -1, 3, -100, 5);
   Group2 := (13, -2, 22, 1, 1242, -12);

   Crowd := Group1 + Group2;
   for Index in ARY_INT'RANGE loop
      Put(Group1(Index), 6);
      Put(Group2(Index), 6);
      Put(Crowd(Index), 6);
      New_Line;
   end loop;

-- Crowd := Group1 - Group2;
-- Crowd := Group1 * Group2;
-- Crowd := Group1 / Group2;
   Crowd := Group1 mod Group2;
-- Crowd := Group1 rem Group2;

end ArrayOp2;




-- Result of execution

--     12    13    25
--     17    -2    15
--     -1    22    21
--      3     1     4
--   -100  1242  1142
--      5   -12    -7

名为e_c19_p4.ada的示例程序演示了如何编写算术数组运算符。这实际上是常见算术运算符的重载。重载这些运算符并不是什么新鲜事,在本教程中您一直都在这么做,因为例如,加号可用于添加整数类型以及固定和浮点类型。没有理由不使用加号逐个元素添加数组,这正是我们将在这里说明的。

“+”函数列在第11行到第18行,是一个非常简单的函数,没有困难的代码。函数名是这个函数的一个不同寻常之处,它的名字是“+”。这是通常的Ada重载操作符的方法,我们在本教程前面已经说明过。定义函数后,使用中缀符号调用函数,如程序的第34行所示,其中Group1的所有6个元素被添加到Group2的相应元素,6个结果被分配到growd的6个元素。加法的结果显示在第35行到第40行,以显示所有元素的总和。

以类似的方式,名为“mod”的函数用于为模运算符提供中缀表示法,并在第45行中调用。其他四个算术运算符在这里没有定义,因为它们与图示的两个非常相似。以这种方式重载mod运算符应该向您指出为什么将mod看作运算符而不是子程序调用很重要。

 

重载规则

重载运算符时必须考虑两个规则,第一个规则是允许对给定运算符执行所需的任意多个重载,前提是输入和结果的参数对于每个重载都有唯一的类型。这是因为系统使用参数的类型和结果的类型来确定每次使用操作符时要使用的重载。这正确地意味着您不能为给定类型重新定义现有运算符的使用。

第二条规则很简单。可以重载现有的Ada运算符,但不能定义Ada中未预定义的中缀运算符。一定要编译并执行这个程序。

 

一元运算符重载

Example program ------> e_c19_p5.ada

                                       -- Chapter 19 - Program 5

procedure UnaryOp is

   type ARY_INT is array(1..6) of INTEGER;

   Crowd, Group1, Group2    : ARY_INT;

   function "+"(In_Array1, In_Array2 : ARY_INT) return ARY_INT is
   Temp_Array : ARY_INT;
   begin
      for Index in ARY_INT'RANGE loop
         Temp_Array(Index) := In_Array1(Index) + In_Array2(Index);
      end loop;
      return Temp_Array;
   end "+";

   function "-"(In_Array1, In_Array2 : ARY_INT) return ARY_INT is
   Temp_Array : ARY_INT;
   begin
      for Index in ARY_INT'RANGE loop
         Temp_Array(Index) := In_Array1(Index) - In_Array2(Index);
      end loop;
      return Temp_Array;
   end "-";

   function "+"(In_Array : ARY_INT) return ARY_INT is
   begin
      return In_Array;
   end "+";

   function "-"(In_Array : ARY_INT) return ARY_INT is
   Temp_Array : ARY_INT;
   begin
      for Index in ARY_INT'RANGE loop
         Temp_Array(Index) := - In_Array(Index);
      end loop;
      return Temp_Array;
   end "-";

begin

   Group1 := (12, 17, -1, 3, -100, 5);
   Group2 := (13, -2, 22, 1, 1242, -12);

   Crowd := Group1 + Group2;
   Crowd := Group1 - Group2;
   Crowd := +Group1;
   Crowd := -Group1;
   Crowd := (Group1 + Group2) - (-Group1 + Group2);

end UnaryOp;




-- Result of execution

-- (There is no output from this program)

检查名为e_c19_p5.ada的程序,以获取重载一元运算符“+”和“-”的示例。第27行到第30行中的函数重载了所定义数组的“+”运算符,因此不太重要,因为这里没有真正完成任何操作。第32到39行中的函数重载“-”运算符并对数组中的每个元素求反。甚至重载“+”运算符似乎都很愚蠢,但这里说明了这一点,当我们研究泛型包时,可以利用这一点。为了编写一个通用的泛型包,可能需要允许使用这样一个看似愚蠢的构造。

一定要编译和运行这个程序,并看到说明重载工作,因为我们已经说过。

 

操作员隐藏

在我们检查过的所有重载中,我们都小心地使用引入了新类型组合的重载,因此从来没有隐藏另一个子程序的实例。如果在嵌套的较低级别声明进一步重载时,类型组合已经以全局方式重载,则全局组合调用的子程序将被隐藏,并且每次都将调用嵌套的子程序。即使重载操作符或标识符时必须小心,也不要害怕使用Ada设计者提供给您的这种强大技术。

 

编程练习

1.修改名为e_c19_p2.ada的程序,将每天的名称与每天的工作小时数一起作为枚举输出输出。(Solution)

2.在名为e_c19_p4.ada的示例程序中为其余四个算术运算符中的任意两个编写函数,并测试这两个新函数。(Solution)

 

---------------------------------------------------------------------------------------------------------------------------

原英文版出处:https://perso.telecom-paristech.fr/pautet/Ada95/a95list.htm

翻译(百度):博客园  一个默默的 *** 的人

 

We declare an uninitialized variable array in line 13, which covers the range of 1 through 12, and an initialized variable array in line 14, which uses the positional aggregate method of initialization. The others portion will fill in positions 9, 10, and 11 with the value of 17. The others construct used in the array aggregate is new in Ada 95. It can only be used with a constrained array and it must be last in the list.

A VERY FLEXIBLE FUNCTION

The function in lines 17 through 27 appears to use an unconstrained array for its formal parameter variable, and it does, but with each use of the function, the formal parameter array is constrained to the limits of the actual variable. When the function is called in line 33 of the program with My_List as the actual array variable, the range of My_List, 1 through 12, is used for the range of the formal parameter in the function. This makes it possible to use the array attributes within the function, in the manner shown, such that they are dependent on which array is used for the actual parameter. When Stuff is used for the actual parameter, the formal parameter will have a range of 4 through 11 within the function. The function can therefore be written in such a way that it has flexibility built into it, even though strong type checking continues to be done, since the function cannot be used with a different unconstrained type if we had one in this example program. Note that all array attributes are available here as they are with any array.

A FEW NOTES ABOUT THIS TYPE

All elements of every variable of type MY_ARRAY will be of type INTEGER, and all indices will be of subtype POSITIVE including the range limits. The variables named My_List and Stuff are of the same type with different limits, so the slice can be used with them. After you study this program, compile and execute it so you can observe the output.

AN ARRAY WITH AN ENUMERATED INDEX

posted @ 2021-04-12 19:40  yangjianfeng  阅读(84)  评论(0编辑  收藏  举报