代码之家  ›  专栏  ›  技术社区  ›  TamaMcGlinn

在不硬编码第一个索引的情况下,如何只使用一个元素初始化数组?

  •  0
  • TamaMcGlinn  · 技术社区  · 6 年前

    我试图将一个无边界的字符串数组传递给一个函数,我不关心索引的范围,因为函数将循环遍历每个元素。

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

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

    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;
    
    3 回复  |  直到 6 年前
        1
  •  4
  •   David Amar    6 年前

    你想要的(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");    
    
        2
  •  5
  •   egilhh    6 年前

    简而言之,所有数组对象都必须被约束,这意味着调用方通常必须决定数组边界。

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

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

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

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

    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子类型进行任何修改,而不影响任何调用方。但是仍然不能保证邪恶的程序员改变数组本身的索引类型…

        3
  •  0
  •   Frédéric Praca    6 年前
    type String_Array is array (Positive range <>) of Unbounded_String;
    

    声明数组类型,但不提供大小。 记住数组有一个静态大小。

    所以 字符串“array'first” 字符串数组范围 什么都不匹配。 如果你声明

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

    然后 米亚尔第一 表示1和 米亚尔山脉 表示1…35。

    只要您不在类型上放置约束,您就不能访问这些属性。