如何使用 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 了解这是如何完成的。
可能还有其他方法,但这些只是我的想法。
另请注意,为简单起见,我只是使用整数作为数组元素。您可以随时制作其他类型的这些数组。
假设我们有一个代表一盒十几个甜甜圈的类型,
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 了解这是如何完成的。
可能还有其他方法,但这些只是我的想法。
另请注意,为简单起见,我只是使用整数作为数组元素。您可以随时制作其他类型的这些数组。