添加两个具有相同标识符的枚举

时间:2020-09-30 16:39:20

标签: raku

是否可以在raku中定义两个具有相同标识符的枚举?

例如,如果我有以下代码:

#!/usr/bin/raku
use v6;

enum Color <Red Blue>;
enum TrafficLight <Red Green>;

sub MAIN(
    Color:D :c(:$color)!, #= the color
    TrafficLight:D :t(:$traffic-light)!, #= the traffic-light
) {
    say "Selected $color, Selected $traffic-light"
}

在这里您可以看到,标识红色是枚举颜色和枚举TrafficLight的一部分。

但是当我执行此脚本时,我得到了Redeclaration-exception:

$ ./test.p6
Potential difficulties:
    Redeclaration of symbol 'Red'
    at /home/martin/mnt/release-notes/./scripts/test.p6:5
    ------> enum TrafficLight <Red Green>⏏;

Usage:
  ./scripts/test.p6 -c|--color=<Color> (Blue Red) -t|--traffic-light=<TrafficLight> (Green Red)

    -c|--color=<Color> (Blue Red)                    the color
    -t|--traffic-light=<TrafficLight> (Green Red)    the traffic-light

有趣的是,当我使用参数-c=Blue and -t=Red执行此脚本时,输出结果是我期望的:

$ ./test.p6 -c=Blue -t=Red
Potential difficulties:
    Redeclaration of symbol 'Red'
    at /home/martin/mnt/release-notes/./scripts/test.p6:5
    ------> enum TrafficLight <Red Green>⏏;
Selected Blue, Selected Red

但是当我使用参数-c=Red and -t=Green执行此脚本时,它根本无法工作,并且返回错误代码2(显示帮助消息)。

我的问题现在是:

  • 是否可以定义两个具有相同名称(但类型不同)的相同Enum-Identifier。也许可以定义一个类似于C ++中的类枚举的枚举,并用namespace包围它们?
  • 是否有可能以某种方式捕获此异常?

谢谢

2 个答案:

答案 0 :(得分:11)

问题在于枚举会在其范围内创建符号。您的代码

enum Color <Red Blue>;
enum TrafficLight <Red Green>;

基本上在做

my \Color = Map.new(Red => 0, Blue => 1) does Enumeration;
my \Red  := Color<Red>;
my \Blue := Color<Blue>;

my \Traffic-Light = Map.new(Red => 0, Green => 1) does Enumeration;
my \Red   := Traffic-Light<Red>;
my \Green := Traffic-Light<Green>;

因此,您可以看到生成警告的原因-在相同的作用域中,创建符号的次数不能超过两次声明$x的次数。尽管如此,两个枚举类仍然存在,并且可以从字符串“ Red”创建值。在这种情况下,我使用的一种解决方案是创建一个程序包并在该程序包中调用枚举:Enum

package Color        {  enum Enum <Red Blue>   }
package TrafficLight {  enum Enum <Red Green>  }

sub MAIN(
    Color::Enum:D        :c(:$color        )!, #= the color
    TrafficLight::Enum:D :t(:$traffic-light)!, #= the traffic-light
) {
    say "Selected $color, Selected $traffic-light"
}

如果要与值匹配,则只需说Color::RedTrafficLight::Green,或者如果将内容存储在模块中以便可以use,则仍然可以使用只是RedGreen,只是不在同一范围内。因此,您可以这样做:

sub MAIN(
    Color::Enum:D        :c(:$color        )!, #= the color
    TrafficLight::Enum:D :t(:$traffic-light)!, #= the traffic-light
) {
    say "Selected $color, Selected $traffic-light"

    { # new scope 
        use MyEnums::Color;
        given $color { 
            when Red   { ... }
            when Green { ... }
        }
    }

    { # separate new scope 
        use MyEnums::TrafficLight;
        ... 
    }
}

答案 1 :(得分:1)

如果只希望导出枚举而不导出枚举中的值,则可以将constantdo块一起使用。

constant Color = do {
  my enum Color <Red Blue>;
  Color
}

constant Traffic-Light = do {
  my enum Traffic-Light <Red Green>;
  Traffic-Light
}

这样做,您只需要按其完全限定的名称或通过哈希访问来访问枚举中的值。

say Color::Red.raku;
say Traffic-Light::Red.raku;

say Color::{'Red'}.raku;
say Traffic-Light::{'Red'}.raku;

say Red; # ERROR: Undeclared name: Red
multi foo ( Color $c ){
  say "the color $c"
}
multi foo ( Traffic-Light::Red ){
  say "stop"
}
multi foo ( Traffic-Light::Green ){
  say "go"
}
multi foo ( Str $s ){
  samewith Traffic-Light::{$s} // Color::{$s}
}

foo Color::Red;  # the color Red
foo Color::Blue; # the color Blue

foo Traffic-Light::Red;   # stop
foo Traffic-Light::Green; # go

foo 'Green'; # go
foo 'Red';   # stop
foo 'Blue';  # the color Blue