如何在 Ada 中动态创建固定大小的数组?
How do I dynamically create a fixed size array in Ada?
作为学习 Ada 的一部分,我正在应对一些基本的编码挑战。我遇到过一种情况,我想创建一个固定大小的二维整数数组(大小在 运行 时间确定)。我的想法是有一个小的实用函数,可以传递数组的大小,创建它,填充它并 return 它用于其他函数。
我该怎么做?我看到的其他答案将创建的数组保留在函数范围内,而不是 return 它。
到目前为止,这是我的主要程序:
with Ada.Integer_Text_IO;
with Ada.Text_IO;
with Coord;
with Grid;
procedure test is
boundary : Coord.Box;
-- This is the array I want to create and fill
-- Note sure about what I put here for the "initial" size
new_grid : Grid.GridType (0 .. 1, 0 .. 1);
begin
-- This is just for the example, actually these
-- values are calculated from values in a text file
Ada.Text_IO.Put ("X Min?");
Ada.Integer_Text_IO.Get (boundary.min.x);
Ada.Text_IO.Put ("X Max?");
Ada.Integer_Text_IO.Get (boundary.max.x);
Ada.Text_IO.Put ("Y Min?");
Ada.Integer_Text_IO.Get (boundary.min.y);
Ada.Text_IO.Put ("Y Max?");
Ada.Integer_Text_IO.Get (boundary.max.y);
new_grid := Grid.get_grid (boundary);
Grid.print (new_grid);
end test;
这是 grid.adb
,其中 get_grid
函数:
with Ada.Integer_Text_IO;
with Ada.Text_IO;
package body Grid is
function get_grid (bounds : Coord.Box) return GridType is
-- This is the grid I'd like to return
new_grid : Grid.GridType (bounds.min.x .. bounds.max.x, bounds.min.y .. bounds.max.y);
begin
for X in bounds.min.x .. bounds.max.x loop
for Y in bounds.min.y .. bounds.max.y loop
new_grid (X, Y) := X + Y;
end loop;
end loop;
return new_grid; -- Needs to persist outsde this function
end get_grid;
-- Print function removed for clarity (this works)
end Grid;
Grid_Type
在 grid.ads
中声明为:
type GridType is array (Integer range <>, Integer range <>) of Integer;
在这些文件中,Coords.Box
只是一个包含 X/Y min/max 个整数的简单记录。
如果我 运行 这个并输入网格大小的合理数字,我会得到 CONSTRAINT_ERROR
。
我已经阅读了 this answer and 和其他一些不太相关的答案,但我还是不明白。
我是 Ada 的新手,但精通其他语言。
数组对象的大小不能在对象声明后改变。虽然这看起来是个问题,但 Ada 提供了在内部块中声明对象的解决方案。
下面的示例将您的数组类型定义为 element_type 的无约束数组。在实际代码中替换您希望数组包含的任何类型。这种不受约束的类型允许您创建具有任何所需维度的类型实例。
type Grid_Type is array(Natural range <>, Natural range <>) of element_type;
在您的函数中读取数组边界信息,然后使用这些数组边界声明一个实例。
function Make_Grid return Grid_Type is
Dim1_Min, Dim1_Max : Natural;
Dim2_Min, Dim2_Max : Natural;
begin
get(Dim1_Min);
get(Dim1_Max);
get(Dim2_Min);
get(Dim2_Max);
declare
New_Grid : Grid_Type(Dim1_Min..Dim1_Max, Dim2_Min..Dim2_Max);
begin
return New_Grid;
end;
end Make_Grid;
内部块使用从输入读取的值创建 Grid_Type 的新实例。该函数只是 returns 内部块中的对象。 Ada 参考手册的第 5.6 节描述了 Ada 块语句。
以下示例演示了它如何适用于整数数组:
package Grids is
type Grid_type is array(Natural range <>, Natural range <>) of Integer;
function make_grid return Grid_Type;
end Grids;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
package body Grids is
---------------
-- make_grid --
---------------
function make_grid return Grid_Type is
Dim1_Min, Dim1_Max : Natural;
Dim2_Min, Dim2_Max : Natural;
begin
Get(Dim1_Min);
Get(Dim1_Max);
Get(Dim2_Min);
Get(Dim2_Max);
declare
New_Grid : Grid_Type(Dim1_Min..Dim1_Max, Dim2_Min..Dim2_Max) :=
(Others =>(Others => 0));
begin
return New_Grid;
end;
end make_grid;
end Grids;
此程序的测试主程序是:
with Ada.Text_IO; use Ada.Text_IO;
with Grids; use Grids;
procedure Grids_Test is
The_Grid : Grid_type := Make_Grid;
begin
Put_Line("Grid Dimensions");
Put_Line(Natural'Image(The_Grid'First(1)) & ".." &
Natural'Image(The_Grid'Last(1)) & " , " &
Natural'Image(The_Grid'First(2)) & "..." &
Natural'Image(The_Grid'Last(2)));
end Grids_Test;
示例执行的输入和输出是:
0
10
20
30
Grid Dimensions
0.. 10 , 20... 30
除了使用声明块来临时保存函数的结果,您还可以使用 Ada.Containers.Indefinite_Holders 来更永久地存储结果。
您需要实例化泛型
use type Grid.Grid_Type; -- necessary to get the "=" operation
package Grid_Holders is new Ada.Containers.Indefinite_Holders(Grid.Grid_Type);
您可以将其声明为
New_Grid : Grid_Holders.Holder;
并且在运行时您可以使用
对其进行初始化
New_Grid := Grid_Holders.To_Holder(Grid.Get_Grid(Boundary));
完成后,您可以使用引用操作访问网格:
Grid.Print(New_Grid.Reference);
如果您想直接访问元素,您可能必须执行以下操作:
Grid.Reference.Element(1,2) := 23;
请注意,某些版本的 GNAT 有一个错误,可能会生成最终化异常。如果是这种情况,您通常可以使用声明块或函数来解决它。声明块示例:
declare
The_Grid : Grid.Grid_Type renames New_Grid.Reference;
begin
The_Grid(1,2) := 23;
end;
这与其他答案的声明块示例不同,因为此声明块不创建任何新网格,它只是访问现有内存。它纯粹是为了解决编译器错误。在此示例中,New_Grid 存在于 declare 块之外,因此它保持可用。
作为学习 Ada 的一部分,我正在应对一些基本的编码挑战。我遇到过一种情况,我想创建一个固定大小的二维整数数组(大小在 运行 时间确定)。我的想法是有一个小的实用函数,可以传递数组的大小,创建它,填充它并 return 它用于其他函数。
我该怎么做?我看到的其他答案将创建的数组保留在函数范围内,而不是 return 它。
到目前为止,这是我的主要程序:
with Ada.Integer_Text_IO;
with Ada.Text_IO;
with Coord;
with Grid;
procedure test is
boundary : Coord.Box;
-- This is the array I want to create and fill
-- Note sure about what I put here for the "initial" size
new_grid : Grid.GridType (0 .. 1, 0 .. 1);
begin
-- This is just for the example, actually these
-- values are calculated from values in a text file
Ada.Text_IO.Put ("X Min?");
Ada.Integer_Text_IO.Get (boundary.min.x);
Ada.Text_IO.Put ("X Max?");
Ada.Integer_Text_IO.Get (boundary.max.x);
Ada.Text_IO.Put ("Y Min?");
Ada.Integer_Text_IO.Get (boundary.min.y);
Ada.Text_IO.Put ("Y Max?");
Ada.Integer_Text_IO.Get (boundary.max.y);
new_grid := Grid.get_grid (boundary);
Grid.print (new_grid);
end test;
这是 grid.adb
,其中 get_grid
函数:
with Ada.Integer_Text_IO;
with Ada.Text_IO;
package body Grid is
function get_grid (bounds : Coord.Box) return GridType is
-- This is the grid I'd like to return
new_grid : Grid.GridType (bounds.min.x .. bounds.max.x, bounds.min.y .. bounds.max.y);
begin
for X in bounds.min.x .. bounds.max.x loop
for Y in bounds.min.y .. bounds.max.y loop
new_grid (X, Y) := X + Y;
end loop;
end loop;
return new_grid; -- Needs to persist outsde this function
end get_grid;
-- Print function removed for clarity (this works)
end Grid;
Grid_Type
在 grid.ads
中声明为:
type GridType is array (Integer range <>, Integer range <>) of Integer;
在这些文件中,Coords.Box
只是一个包含 X/Y min/max 个整数的简单记录。
如果我 运行 这个并输入网格大小的合理数字,我会得到 CONSTRAINT_ERROR
。
我已经阅读了 this answer and
我是 Ada 的新手,但精通其他语言。
数组对象的大小不能在对象声明后改变。虽然这看起来是个问题,但 Ada 提供了在内部块中声明对象的解决方案。
下面的示例将您的数组类型定义为 element_type 的无约束数组。在实际代码中替换您希望数组包含的任何类型。这种不受约束的类型允许您创建具有任何所需维度的类型实例。
type Grid_Type is array(Natural range <>, Natural range <>) of element_type;
在您的函数中读取数组边界信息,然后使用这些数组边界声明一个实例。
function Make_Grid return Grid_Type is
Dim1_Min, Dim1_Max : Natural;
Dim2_Min, Dim2_Max : Natural;
begin
get(Dim1_Min);
get(Dim1_Max);
get(Dim2_Min);
get(Dim2_Max);
declare
New_Grid : Grid_Type(Dim1_Min..Dim1_Max, Dim2_Min..Dim2_Max);
begin
return New_Grid;
end;
end Make_Grid;
内部块使用从输入读取的值创建 Grid_Type 的新实例。该函数只是 returns 内部块中的对象。 Ada 参考手册的第 5.6 节描述了 Ada 块语句。
以下示例演示了它如何适用于整数数组:
package Grids is
type Grid_type is array(Natural range <>, Natural range <>) of Integer;
function make_grid return Grid_Type;
end Grids;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
package body Grids is
---------------
-- make_grid --
---------------
function make_grid return Grid_Type is
Dim1_Min, Dim1_Max : Natural;
Dim2_Min, Dim2_Max : Natural;
begin
Get(Dim1_Min);
Get(Dim1_Max);
Get(Dim2_Min);
Get(Dim2_Max);
declare
New_Grid : Grid_Type(Dim1_Min..Dim1_Max, Dim2_Min..Dim2_Max) :=
(Others =>(Others => 0));
begin
return New_Grid;
end;
end make_grid;
end Grids;
此程序的测试主程序是:
with Ada.Text_IO; use Ada.Text_IO;
with Grids; use Grids;
procedure Grids_Test is
The_Grid : Grid_type := Make_Grid;
begin
Put_Line("Grid Dimensions");
Put_Line(Natural'Image(The_Grid'First(1)) & ".." &
Natural'Image(The_Grid'Last(1)) & " , " &
Natural'Image(The_Grid'First(2)) & "..." &
Natural'Image(The_Grid'Last(2)));
end Grids_Test;
示例执行的输入和输出是:
0
10
20
30
Grid Dimensions
0.. 10 , 20... 30
除了使用声明块来临时保存函数的结果,您还可以使用 Ada.Containers.Indefinite_Holders 来更永久地存储结果。
您需要实例化泛型
use type Grid.Grid_Type; -- necessary to get the "=" operation
package Grid_Holders is new Ada.Containers.Indefinite_Holders(Grid.Grid_Type);
您可以将其声明为
New_Grid : Grid_Holders.Holder;
并且在运行时您可以使用
对其进行初始化New_Grid := Grid_Holders.To_Holder(Grid.Get_Grid(Boundary));
完成后,您可以使用引用操作访问网格:
Grid.Print(New_Grid.Reference);
如果您想直接访问元素,您可能必须执行以下操作:
Grid.Reference.Element(1,2) := 23;
请注意,某些版本的 GNAT 有一个错误,可能会生成最终化异常。如果是这种情况,您通常可以使用声明块或函数来解决它。声明块示例:
declare
The_Grid : Grid.Grid_Type renames New_Grid.Reference;
begin
The_Grid(1,2) := 23;
end;
这与其他答案的声明块示例不同,因为此声明块不创建任何新网格,它只是访问现有内存。它纯粹是为了解决编译器错误。在此示例中,New_Grid 存在于 declare 块之外,因此它保持可用。