添加两个共享一些相同标识符的枚举

Adding two enums that share some same identifiers

是否可以在 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"
}

你可以在这里看到,红色标识符是枚举颜色和枚举交通灯的一部分。

但是当我执行这个脚本时,我得到了重新声明异常:

$ ./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 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;
        ... 
    }
}

如果您只想导出枚举而不是枚举中的值,您可以使用带有 do 块的 constant

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