如何将枚举转换为整数以处理 overflow/wraparound?
How do I cast an enum to an Integer to handle overflow/wraparound?
我正在学习 ada,我正在尝试为枚举实现加法重载。
基本上我希望能够将一个整数添加到 Day 类型并获得生成的 Day 值。所以星期一 + 2 => 星期三。
这是我的简化代码:
procedure overload is
type Day is (
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
);
day1 : Day := Monday;
function "+" (left: Day; right: Integer) return Day is
-- how would I handle this here? I want to basically say
-- if Day + Integer > Saturday then
-- wraparound back to Sunday
return DayValue;
begin
for x in 0 .. 7 loop
Ada.text_io.put_line("Monday + " & Integer'Image(x) & " = " & Day'Image(day1 + x));
end loop;
end overload;
您可以使用'Pos 和'Val 属性来完成。 'Pos returns 提供的日期相对于第一个选项(索引为 0)的位置,而 'Val 采用 Pos 值和 returns 日期类型值:
return Day'Val(Day'Pos(Left) + Right);
对于环绕检查星期六的'Pos 值与左+右值的'Pos 值并使用星期日的Day'Val(0)
或者将您的 Right 输入类型从 Integer 切换为 Natural 并使用模数数学:
return Day'Val((Day'Pos(left) + Right) mod 7);
你甚至可以花点心思,为 7 设置一个常量:
Day_Mod : constant := Day'Pos(Day'Last) - Day'Pos(Day'First) + 1;
然后变成
return Day'Val((Day'Pos(left) + Right) mod Day_Mod);
虽然您有一个获取与枚举值关联的位置值的答案,但不要认为这与 C 中的枚举相同。Ada 枚举不是数字类型。
您可以使用 for 循环遍历一系列枚举值,如
for the_day in Day loop in loop
Put_Line(Day'Image(the_day));
end loop;
如果要打印当天和第二天可以使用'Succ属性。
for the_day in Day loop
Put(Day'Image(the_day) & " the next day is ");
if the_day = Day'Last then
Put_Line(Day'Image(Day'First));
else
Put_Line(Day'Image(the_day'Succ));
end if;
end loop;
我会使用 PragmARC.Wrapping
:
with PragmARC.Wrapping;
function "+" (Left : Day; Right : Integer) return Day is
package Wrapping is new PragmARC.Wrapping (Item => Day);
use Wrapping;
Result : Day := Left;
begin -- "+"
Change : for I in 1 .. abs Right loop
Result := (if Right < 0 then Wrap_Pred (Result) else Wrap_Succ (Result) );
end loop Change;
return Result;
end "+";
我正在学习 ada,我正在尝试为枚举实现加法重载。
基本上我希望能够将一个整数添加到 Day 类型并获得生成的 Day 值。所以星期一 + 2 => 星期三。
这是我的简化代码:
procedure overload is
type Day is (
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
);
day1 : Day := Monday;
function "+" (left: Day; right: Integer) return Day is
-- how would I handle this here? I want to basically say
-- if Day + Integer > Saturday then
-- wraparound back to Sunday
return DayValue;
begin
for x in 0 .. 7 loop
Ada.text_io.put_line("Monday + " & Integer'Image(x) & " = " & Day'Image(day1 + x));
end loop;
end overload;
您可以使用'Pos 和'Val 属性来完成。 'Pos returns 提供的日期相对于第一个选项(索引为 0)的位置,而 'Val 采用 Pos 值和 returns 日期类型值:
return Day'Val(Day'Pos(Left) + Right);
对于环绕检查星期六的'Pos 值与左+右值的'Pos 值并使用星期日的Day'Val(0)
或者将您的 Right 输入类型从 Integer 切换为 Natural 并使用模数数学:
return Day'Val((Day'Pos(left) + Right) mod 7);
你甚至可以花点心思,为 7 设置一个常量:
Day_Mod : constant := Day'Pos(Day'Last) - Day'Pos(Day'First) + 1;
然后变成
return Day'Val((Day'Pos(left) + Right) mod Day_Mod);
虽然您有一个获取与枚举值关联的位置值的答案,但不要认为这与 C 中的枚举相同。Ada 枚举不是数字类型。
您可以使用 for 循环遍历一系列枚举值,如
for the_day in Day loop in loop
Put_Line(Day'Image(the_day));
end loop;
如果要打印当天和第二天可以使用'Succ属性。
for the_day in Day loop
Put(Day'Image(the_day) & " the next day is ");
if the_day = Day'Last then
Put_Line(Day'Image(Day'First));
else
Put_Line(Day'Image(the_day'Succ));
end if;
end loop;
我会使用 PragmARC.Wrapping
:
with PragmARC.Wrapping;
function "+" (Left : Day; Right : Integer) return Day is
package Wrapping is new PragmARC.Wrapping (Item => Day);
use Wrapping;
Result : Day := Left;
begin -- "+"
Change : for I in 1 .. abs Right loop
Result := (if Right < 0 then Wrap_Pred (Result) else Wrap_Succ (Result) );
end loop Change;
return Result;
end "+";