如何使用Ada 2012用户定义的迭代器?

时间:2016-01-19 16:49:01

标签: iterator ada

Ada 2012用户定义的迭代器

此功能允许用户创建自定义迭代器。可以写Get (List, Index)而不是写List (Index)而不是写for Index in 1 .. List.Max,而不是写for Index in List'Range。如果list不是数组,我不确定List'Range是否可行,也许用户定义的迭代器还有另一种语法。

  • 如何使用Ada 2012用户定义的迭代器?
  • 最好:如何在示例中实现用户定义的迭代器?

实施例

这是一个Stack或LIFO示例。下一步是隐藏type Stack成员并为type Stack List实现用户定义的迭代器。

with Ada.Text_IO;
with Ada.Integer_Text_IO;

procedure Main is

   use Ada.Text_IO;
   use Ada.Integer_Text_IO;

   type Integer_Array is array (Integer range <>) of Integer;

   type Stack (Count : Natural) is record
      List : Integer_Array (1 .. Count);
      Top : Natural := 0;
   end record;

   procedure Push (Item : Integer; Result : in out Stack) is
   begin
      Result.Top := Result.Top + 1;
      Result.List (Result.Top) := Item;
   end;

   S : Stack (10);

begin

   Push (5, S);
   Push (3, S);
   Push (8, S);

   for I in S.List'First .. S.Top loop
      Put (S.List (I), 2);
      New_Line;
   end loop;

   --for I in S'Range loop
      --Put (S (I), 2);
      --New_Line;
   --end loop;
end;

3 个答案:

答案 0 :(得分:3)

S'Range的使用不适用于容器,仅适用于标准数组。这不能改变。

您可能会说for C in S.Iterate loop调用函数Iterate并返回循环的每个步骤的游标。此时,您需要使用Element (C)来访问实际元素(或者更有效Reference (C)

第三个版本是for E of S loop,它直接返回该元素。您无权访问相应的光标。这通常是编写循环的首选方法,除非迭代遍历地图的整个内容,因为无法访问密钥,只能访问该值。

有关如何在自己的数据结构中添加对这些循环的支持的更多信息,您可以查看AdaCore发布的两个宝石:

我应该提供你需要的所有信息。

答案 1 :(得分:1)

您可以在Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); 循环中使用迭代器,如下所示:

for

或者更懒惰的版本:

for C in S.Iterator loop
   Put (S (C));
   New_Line;
end loop;

实现迭代器是一个相当长的故事,我引用了Ada 2012 rationale(@trashgod也提到过)的详细解释。

答案 2 :(得分:1)

我不确定是否能够迭代堆栈的内容是堆栈正常用例的一部分!除此之外,这是您可以使用广义迭代(ARM 5.5.2)编写的代码:

with Ada.Text_IO;
with Stacks;
procedure Iteration is
   use Ada.Text_IO;
   S : Stacks.Stack (10);
begin
   Stacks.Push (S, 5);
   Stacks.Push (S, 3);
   Stacks.Push (S, 8);

   for C in Stacks.Iterate (S) loop
      Put_Line (Stacks.Element (C)'Img);                                            --'
   end loop;
end Iteration;

这是Stacks的可能规范。请注意,System仅用于私有部分。

with Ada.Iterator_Interfaces;
private with System;
package Stacks is

这些是基本Stack抽象的一部分。请注意,如果您希望能够编写索引访问(My_Stack (42)或循环for E of My_Stack loop...),则事情会变得复杂得多。首先,必须标记Stack

   type Stack (Count : Natural) is private;

   procedure Push (To : in out Stack; Item : Integer);

   function Element (S : Stack; Index : Positive) return Integer;

公共部分的其余部分是支持广义迭代。

   type Cursor is private;
   function Has_Element (Pos : Cursor) return Boolean;
   function Element (C : Cursor) return Integer;

   package Stack_Iterators
     is new Ada.Iterator_Interfaces (Cursor, Has_Element);

   function Iterate (S : Stack)
                    return Stack_Iterators.Forward_Iterator’Class;                  --'
private                                                                             --'
   type Integer_Array is array (Positive range <>) of Integer;

   type Stack (Count : Natural) is record
      List : Integer_Array (1 .. Count);
      Top : Natural := 0;
   end record;

   function Element (S : Stack; Index : Positive) return Integer
     is (S.List (Index));

Cursor需要引用对象 的游标。我已使用System.Address来避免使用访问类型并需要Stack s aliased

   type Cursor is record
      The_Stack : System.Address;
      List_Index : Positive := 1;
   end record;
end Stacks;

包裹体......

with System.Address_To_Access_Conversions;
package body Stacks is
   procedure Push (To : in out Stack; Item : Integer) is
   begin
      To.Top := To.Top + 1;
      To.List (To.Top) := Item;
   end Push;

我们必须将Stack地址转换为指针指向Stack s。

   package Address_Conversions
     is new System.Address_To_Access_Conversions (Stack);

   function Has_Element (Pos : Cursor) return Boolean is
      S : Stack renames Address_Conversions.To_Pointer (Pos.The_Stack).all;
   begin
      return Pos.List_Index <= S.Top;
   end Has_Element;

   function Element (C : Cursor) return Integer is
      S : Stack renames Address_Conversions.To_Pointer (C.The_Stack).all;
   begin
      return S.List (C.List_Index);
   end Element;

现在为实际的迭代器;我只做过正版。

   type Iterator is new Stack_Iterators.Forward_Iterator with record
      The_Stack : System.Address;
   end record;
   overriding function First (Object : Iterator) return Cursor;
   overriding function Next (Object : Iterator; Pos : Cursor) return Cursor;

   function Iterate (S : Stack)
                    return Stack_Iterators.Forward_Iterator'Class is                   --'
   begin
      --  I seem to be relying on S being passed by reference.
      --  This would be OK anyway if Stack was tagged; but it is a
      --  reasonable bet that the compiler will pass a large object
      --  by reference.
      return It : Iterator do
         It.The_Stack := S’Address;                                                     --'
      end return;                                                                   --'
   end Iterate;

   function First (Object : Iterator) return Cursor is
   begin
      return C : Cursor do
         C.The_Stack := Object.The_Stack;
         C.List_Index := 1;
      end return;
   end First;

   function Next (Object : Iterator; Pos : Cursor) return Cursor is
      pragma Unreferenced (Object);
   begin
      return C : Cursor do
         C.The_Stack := Pos.The_Stack;
         C.List_Index := Pos.List_Index + 1;
      end return;
   end Next;
end Stacks;