如何在不对第一个索引进行硬编码的情况下初始化一个只有一个元素的数组?

How do you initialize an array with only one element, without hardcoding the first index?

我正在尝试将 Unbounded_String 的数组传递给一个函数,我不关心索引的范围,因为函数将遍历每个元素。

(element1, element2) 语法自动从范围内的第一个索引值开始,然后递增给定的第二个值,这适用于多个值。但是,对于单个值,这不能使用,因为括号被认为是多余的。

此代码显示了我所做的每次尝试的错误消息。 (1) 有效,但传递单元素数组的首选语法 (2) 无效。 (3) 有效,并作为 this similar question 的答案给出。但是,这会将范围的第一个索引硬编码到调用方;如果 String_Array 实现发生变化,则必须更改所有调用站点,即使它们不关心使用的索引值。

with Ada.Strings.Unbounded;  use Ada.Strings.Unbounded;

procedure Main is

  function "+"(S: String) return Ada.Strings.Unbounded.Unbounded_String
    renames Ada.Strings.Unbounded.To_Unbounded_String;

  type String_Array is array (Positive range <>) of Unbounded_String;

  procedure Foo(input : in String_Array) is
  begin
    null;
  end Foo;

begin
  Foo((+"one", +"two"));                                    --(1)
  --Foo((+"only"));                                         --(2) positional aggregate cannot have one component
  Foo((1 => +"only"));                                      --(3)
  --Foo((String_Array'First => +"only"));                   --(4) prefix for "First" attribute must be constrained array
  --Foo((String_Array'Range => +"only"));                   --(5) prefix for "Range" attribute must be constrained array
  --Foo((String_Array'Range'First => +"only"));             --(6) range attribute cannot be used in expression
  --Foo((String_Array'Range'Type_Class'First => +"only"));  --(7) range attribute cannot be used in expression
end Main;

简短的回答是必须约束所有数组对象,这意味着调用者通常必须决定数组边界。

但是,您知道索引类型,并且可以这样做

Foo((Positive'First => +"only"));

这并没有真正回答你的问题,因为有人可能仍然 fiddle 数组范围,而且实际上没有任何防范措施。

添加一个新的子类型作为范围可能是一个可行的解决方案,但是:

subtype String_Array_Range is Positive;
type String_Array is array (String_Array_Range range <>) of Unbounded_String;
...
Foo((String_Array_Range'First => +"only"));

现在可以在 String_Array_Range 子类型上进行任何调整,而不会影响任何调用者。但是仍然不能保证不被邪恶的程序员更改数组本身的索引类型...

type String_Array is array (Positive range <>) of Unbounded_String;

声明一种数组但不提供大小。 请记住,数组具有静态大小。

所以 String_Array'FirstString_Array'Range 不匹配任何东西。 如果你声明

type my_String_Array is String_Array(1 .. 35);
my_arr : my_String_Array

my_arr'第一个表示1,my_arr'范围表示1..35.

只要您不对类型进行约束,就无法访​​问这些属性。

你想要的 (2) 确实是不可能的,因为它可能被误认为是括号表达式(参见 http://www.adaic.org/resources/add_content/standards/12aarm/html/AA-4-3-3.html 注 10)。

如果您确实出于您陈述的原因想要避免表达式 (3),作为解决方法,您可以定义一个函数来处理单元素数组的情况:

function Singleton_String_Array (S: String) return String_Array is ((1 => + S));
-- one element call
Foo(Singleton_String_Array ("only"));

它重用了您的表达式 (3),但第一个索引硬编码不再在调用站点上完成。

您还可以重载 foo 函数来处理特殊的单元素情况:

   procedure Process_String (input : in Ada.Strings.Unbounded.Unbounded_String) is
   begin
      null;
   end Process_String;

   procedure Foo(input : in String_Array) is
   begin
      for string of input loop
         Process_String (string);
      end loop;
   end Foo;

   procedure Foo(input : in Ada.Strings.Unbounded.Unbounded_String) is
   begin
      Process_String (input);
   end Foo;
   -- One element call
   Foo(+"only");