Ada:具有可变大小的数组属性的对象

alu*_*iak 4 generics ada dynamic-arrays

我想在一个包内创建一个标记类型,描述一个2D离散空间,其大小由运行时间决定.(背景:生命游戏的实施)

我找到的第一种方法是通用性:

generic
    Size : Natural;
package Worlds is
    type World_Type is tagged private;
    type World is access World_Type'Class;
    subtype Coordinate is Positive range 1..Size;
private
    type World_Array is array (Coordinate, Coordinate) of Boolean;
    type World_Type is tagged record
            Content : World_Array;
    end record;
end Worlds;
Run Code Online (Sandbox Code Playgroud)

但是,在为世界实现访问者时,通用性成为一个大问题:

with Worlds;

package World_Visitors is
    type World_Visitor_Type is tagged private;
    type World_Visitor is access World_Visitor_Type'Class;

    procedure Visite(v : World_Visitor_Type;
                     w : in out Worlds.World); -- ERROR: invalid prefix in selected component "Worlds"
private
    type World_Visitor_Type is tagged null record;
end World_Visitors;
Run Code Online (Sandbox Code Playgroud)

GNAT无法编译,因为Worlds是一个通用包.然后,因为我不想为每个可能的世界大小编写一个Visitor,我尝试C++方式:在标记类型中声明size为属性.

package Worlds is
    type World_Type is tagged private;
    type World is access World_Type'Class;
    subtype Coordinate is Positive range <>;

    function Init(Size : Natural) return World; -- initialize Content attribute as an array of length (Size*Size)
private
    type World_Array is array (Coordinate, Coordinate) of Boolean;
    type World_Type is tagged record
            Content : World_Array;
            Size    : Natural;
    end record;
end Worlds;
Run Code Online (Sandbox Code Playgroud)

而且,预计这不起作用,因为World_Array需要一个显着的坐标范围.实际上,我不知道如何在标记类型中创建运行时选择大小的数组.我从这里,这里,这里这里得到了一些想法,但在这种情况下似乎没有任何意义.

Ada如何实现具有可变大小数组属性的对象?

Sim*_*ght 9

解决这个问题的正常Ada方法是使用判别式(参见ARM 3.7).

在你的情况下,这看起来像

package Worlds is
   type World_Type (Size : Natural) is tagged private;
   type World is access World_Type’Class;          -- ‘’ to fix SO colour bug
private
   type World_Array is array (Positive range <>, Positive range <>) of Boolean;
   type World_Type (Size : Natural) is tagged record
      Content : World_Array (1 .. Size, 1 .. Size);
   end record;
end Worlds;
Run Code Online (Sandbox Code Playgroud)

其中World_Array无约束数组类型的示例(ARM 3.6).你可以通过代码创建一个新的世界

W : Worlds.World := new Worlds.World_Type (Size => 100);
Run Code Online (Sandbox Code Playgroud)

请注意,Size在创建对象后无法更改.

我遗漏了Coordinate; 并且你可能会离开Init,特别是如果你提供初始化器Content:

      Content : World_Array (1 .. Size, 1 .. Size) :=
        (others => (others => False));
Run Code Online (Sandbox Code Playgroud)

编辑26.iii.15:代码正在创建一个Size + 1x 大小的数组Size + 1.