如何使用 Ada 中的枚举在数组中声明一个范围?

How do I declare a range within an array using an enumeration in Ada?

假设我们有一个代表一盒十几个甜甜圈的类型,

type Bakers_Dozen is range 1 to 13;  -- Indices from 1 to 6 are donuts

每个 Donut 都有一个在 Bakers_Dozen:

范围内的唯一值
subtype Donut is Bakers_Dozen (Plain, Chocolate, Strawberry, Glazed, Blueberry, Cannabis);
for Donut use (Plain=>1, Chocolate=>2, Strawberry=>3, Glazed=>4, Blueberry=>5, Cannabis=>6);  

目的是通过名称或值来引用甜甜圈,并确保它仅占据数组的范围 1..6。

不幸的是,我的代码导致错误消息“这种类型的约束不正确”。

  PastriesBox[Plain].Message = "Plain Donut is boring but costs less";
  PastriesBox[Donut'Last].Message = "Please read contradictions and disclaimer inside box.";
  PastriesBox[12].Message = "A great tasting muffin with fresh goat milk.";

有没有办法将数组的范围声明为枚举?

如果您的基类型是整数类型,则子类型是整数类型。你不能使它成为一个枚举类型。

如果你愿意,你可以为你的甜甜圈声明常量,然后你可以通过名称引用它们。您可以改为给其他值命名,然后让 Bakers_Dozen 成为枚举类型。如果算术运算在语义上对您的类型的值没有意义,那么它无论如何都不应该是整数类型。

您可以通过一些不同的方式来执行此操作。最简单的方法是使用 Donuts 作为索引并使用 Bakers_Dozen 作为数组的元素类型来声明一个常量数组。然后你只需要使用数组来转换索引:

package Indexes is
    type Bakers_Dozen is range 1 .. 13;  -- Indices from 1 to 6 are donuts
    type Donut is  
        (Plain, 
         Chocolate, 
         Strawberry, 
         Glazed, 
         Blueberry, 
         Cannabis);
    
    To_Index : constant array (Donut'Range) of Bakers_Dozen :=
        (Plain      => 1,
         Chocolate  => 2,
         Strawberry => 3,
         Glazed     => 4,
         Blueberry  => 5,
         Cannabis   => 6);
    
    
end Indexes;

那么你可以这样做:

P1 : array(Indexes.Bakers_Dozen'Range) of Integer;

P1(Indexes.To_Index(Indexes.Plain)) := 2;

此方法的替代方法是确保 Donuts 与 Bakers_Dozen 大小相同,然后使用 Ada.Unchecked_Conversion 将 Donut 对象转换为 Bakers_Dozen 对象

package Conversions is
    type Bakers_Dozen is range 1 .. 13;  -- Indices from 1 to 6 are donuts
    type Donut is 
        (Plain, 
         Chocolate, 
         Strawberry, 
         Glazed, 
         Blueberry, 
         Cannabis)
    with Size => Bakers_Dozen'Size;
    
    for Donut use
        (Plain      => 1,
         Chocolate  => 2,
         Strawberry => 3,
         Glazed     => 4,
         Blueberry  => 5,
         Cannabis   => 6);
         
    function To_Index is new Ada.Unchecked_Conversion(Donut,Bakers_Dozen);
    
end Conversions;

那么你可以这样做:

P2 : array(Conversions.Bakers_Dozen'Range) of Integer;

P2(Conversions.To_Index(Conversions.Chocolate)) := 3;

如果你想要花哨一些,你也可以将其中一个方法包装到私有类型中,并使用更高级的概念,例如 "Reference_Type" objects and the aspects Variable_Indexing and Constant_Indexing 让你的私有类型像数组一样工作

package Wrappers is

    type Bakers_Dozen is range 1 .. 13;  -- Indices from 1 to 6 are donuts
    type Donut is 
        (Plain, 
         Chocolate, 
         Strawberry, 
         Glazed, 
         Blueberry, 
         Cannabis);
         
    type Bakers_Array is tagged private
    with
        Variable_Indexing => Element;
        
    type Element_Holder(Element : access Integer) is null record
        with Implicit_Dereference => Element;
        
    function Element
        (Self  : aliased in out Bakers_Array;
         Index : Donut)
         return Element_Holder;
    function Element
        (Self  : aliased in out Bakers_Array;
         Index : Bakers_Dozen)
         return Element_Holder;
         
    

private

    type Element_Array is array (Bakers_Dozen'Range) of aliased Integer;

    type Bakers_Array is tagged record
        Elements : Element_Array;
    end record;
    
    To_Index : constant array (Donut'Range) of Bakers_Dozen :=
        (Plain      => 1,
         Chocolate  => 2,
         Strawberry => 3,
         Glazed     => 4,
         Blueberry  => 5,
         Cannabis   => 6);
    
    function Element
        (Self  : aliased in out Bakers_Array;
         Index : Donut)
         return Element_Holder
    is (Element => Self.Elements(To_Index(Index))'Access);
    
    function Element
        (Self  : aliased in out Bakers_Array;
         Index : Bakers_Dozen)
         return Element_Holder
    is (Element => Self.Elements(Index)'Access);

end Wrappers;

那么你可以这样做:

P3 : Wrappers.Bakers_Array;

P3(Wrappers.Strawberry) := 4;

注意:我没有添加 Constant_Indexing 方面来节省打字时间,但您可能也想要它。您可以查看 Ada.Containers.Vectors 了解这是如何完成的。

可能还有其他方法,但这些只是我的想法。

另请注意,为简单起见,我只是使用整数作为数组元素。您可以随时制作其他类型的这些数组。