包含可变长度字符串的记录数组

An array of records containing variable-length strings

我想要一个包含整数和可变长度字符串的记录,如下所示:

type Entry is
record
    Value: Integer;
    Label: String;
end record;

我 运行 the issue 认为你不能将不受约束的字符串放入记录类型中,所以按照当时的建议 link 我尝试了

type Entry(Label_Length : Natural) is
record
    Value: Integer;
    Label: String(1..Label_Length);
end record;

但现在的问题是,我想要这些东西的数组:

Entries : Array(1..2) of Entry := (
    (Label_Length => 0, Value => 1, Label => ""),
    (Label_Length => 0, Value => 2, Label => "")
);

有人告诉我

main.adb:17:28: unconstrained element type in array declaration

我只想声明一个包含这些东西的(常量)数组,并以直观的方式输入标签和值(我已经对必须计算字符串长度并输入 Label_Length 手动)。我该怎么做?

[entry 是保留字。]

如果您想要一个数组,所有条目的大小必须相同。第二条记录的大小是 Label_Length (4) + Value (4) + Label (Character (1) * Label_Length) 即介于 8刚好超过 2**31 个字节。

诀窍是固定最大大小并给出默认值:

   subtype Ent_Label_Length is Natural range 0 .. 32;

   type Ent (Label_Length : Ent_Label_Length := Ent_Label_Length'Last) is
      record
         Value : Integer;
         Label : String (1 .. Label_Length);
      end record;

您可以使用 Ada.Strings.Bounded (ARM A.4.4).

来省去编写此代码(以及计算每个字符串的长度)的麻烦

如果您不知道标签字段的最大大小,您可以使用 Ada.Strings.Unbounded。

with Ada.Strings.Unbounded;    use Ada.Strings.Unbounded;
with Ada.Text_IO.Unbounded_IO; use Ada.Text_IO.Unbounded_IO;
with Ada.Text_IO;              use Ada.Text_IO;
with Ada.Integer_Text_IO;      use Ada.Integer_Text_IO;

procedure Main is
   type Ent is record
      Value : Integer;
      Label : Unbounded_String;
   end record;

   type ent_array is array (1 .. 4) of Ent;

   Foo : ent_array;
begin
   for I of Foo loop
      Put ("Enter a value: ");
      Get (I.Value);
      Skip_Line;
      Put ("Enter a label: ");
      I.Label := Get_Line;
      New_Line;
   end loop;

   Put_Line ("Array Foo contents:");
   for I of Foo loop
      Put (I.Value'Image & " ");
      Put_Line (I.Label);
   end loop;
end Main;

如果您不介意略有不同的语法,您也可以考虑使用 Ada.Containers.Indefinite_Vectors 包代替数组。然后每个元素可以是不同的大小。向量可以像数组一样用于 for 循环:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Vectors; use Ada.Containers;

procedure Main is
    
    type Entry_Info(Label_Length : Natural) is
    record
        Value: Integer;
        Label: String(1..Label_Length);
    end record;
    
    package Vectors is new Indefinite_Vectors
        (Index_Type   => Positive,
         Element_Type => Entry_Info);
         
    use type Vectors.Vector;  -- so you can use the & operator
         
    Entries : Vectors.Vector := Vectors.Empty_Vector
        & (Label_Length => 0, Value => 1, Label => "")
        & (Label_Length => 1, Value => 2, Label => "A");
        
begin
    for Info of Entries loop
        Put_Line(Info.Value'Image & " => " & Info.Label);
    end loop;
end Main;

还有一个但可能更粗糙的方法是将字符串放在堆上并使用访问值:

type String_Ref is access String;
    
type Entry_T is record
  Value: Integer;
  Label: String_Ref;
end record;

要分配字符串,请使用带有初始值的“new”:

Entries : constant array(1..2) of Entry_T := (
  (Value => 1, Label => new String'("First entry")),
  (Value => 2, Label => new String'("Second entry"))
);

要获取 Label 的值,请遵循“.all”:

for E of Entries loop
   Ada.Text_IO.Put_Line (
        "Value" & E.Value'Image
      & ", label " & E.Label.all);
end loop;

如果我们发布奇怪的解决方案,您也可以使用支架:

package String_Holders is new Ada.Containers.Indefinite_Holders
   (Element_Type => String);

type Entry_Is_Reserved is record
   Value : Integer;
   Label : String_Holders.Holder;
end record;