[NAME] ALL.dao.type.enum [TITLE] 枚举符号类型 [DESCRIPTION] 枚举类型enum定义了一组名称符号,其中每个符号表示一个特定的整数值。 这种类型可用于表示一组状 态或标识。 道语言还支持了一种称作符号特殊的枚举类型,使得枚举类型的使用变得极为方便。 0.1 定义 1 EnumEntry ::= Identifier [ = ConstExpr ] 2 3 Enum1 ::= 'enum' Identifier '{' EnumEntry { ',' EnumEntry } '}' 4 Enum2 ::= 'enum' Identifier '{' EnumEntry { ';' EnumEntry } '}' 5 6 Enum ::= Enum1 | Enum2 7 8 EnumType1 ::= 'enum' '<' EnumEntry { ',' EnumEntry } '>' 9 EnumType2 ::= 'enum' '<' EnumEntry { ';' EnumEntry } '>' 10 11 EnumType ::= EnumType1 | EnumType2 12 13 Symbol ::= '$' Identifier Enum1(EnumType1)的定义与 Enum2(EnumType2)的定义的唯一区别就是 前者使用了逗号,而后者使用了 分号。 这样的结果是,以逗号定义的枚举类型,它们的符号不可组合; 而以分号定义的枚举类型,它们的 符号则可以组合。 为了方便起见,符号可以组合的枚举类型将被称作标识枚举, 而符号不可组合的枚举 类型将被称作状态枚举。 0.2 状态枚举 下面是个简单的状态枚举类型。这个定义使用了类似C++里的语法: 1 enum MyEnum 2 { 3 AA , # 0 4 BB = 3, # 3 5 CC # 4 6 } 跟C++里一样,状态枚举里的第一个符号如果没有显式赋值,那么它将被自动地赋为零。 其它未被赋值的 符号,它们的值将自动地从它们前面符号的值加一获得。 这些符号只能通过相应的枚举类型来访问, 应为它们并没有出现在当前的命名空间。 1 var a = MyEnum::AA # Or: MyEnum.AA; 因为MyEnum的符号不可组合,变量e将只能取 MyEnum的一个值或符号。 0.3 符号枚举 为了方便起见,符号枚举将先于标识枚举被介绍。 道语言里,可直接使用的枚举符号是由普通的标识符前 加货币符号$构成。 它们通常是与枚举类型一起使用才有特定的意义。 1 enum E1 { AA=1, BB=2 } 2 enum E2 { AA=10, BB=20 } 3 4 var e1: E1 = $AA 5 var e2: E2 = $AA 6 7 io.writeln( e1 ) # 输出: $AA(1) 8 io.writeln( e2 ) # 输出: $AA(10) 尽管是同一个符号,"$AA"在分别赋给"e1"和"e2"时,被自动地做了不同的处理。 在赋给"e1"时,"$AA"以 等同E1::AA处理,而在赋给"e2"时,"$AA"以等同E2::AA处理。 因此符号所表达的东西将取决于它被用作 的枚举类型。 0.4 标识枚举 标识枚举的定义和状态枚举的定义语法上基本一致,只不过标识枚需要使用分号而不是逗号。 1 enum MyEnum 2 { 3 AA ; # 1 4 BB = 3; # 3 5 CC # 6 6 } 除了语法的差异,标识枚举对未显式赋值的符号的处理也不一样。 这里,标识枚举里的第一个符号如果没 有显式赋值,那么它将被自动地赋为一。 其它未被赋值的符号,它们的值将自动地从它们前面符号的值按 比特位左移一位获得。 值得注意的是,枚举类型里的符号可以被任意赋值,因此,这将取决于用户给它们 赋 有意义的值。 作为标识枚举类型,它们的符号可被自由组合,因此它们可有效地用作标识: 1 enum Orientation 2 { 3 East ; 4 West ; 5 South ; 6 North 7 } 8 var orientation = Orientation::East + Orientation::South 9 io.writeln( orientation ) # Output: $East$South(5) 0.5 枚举类型名 使用枚举类型的另一种方式是使用枚举类型的类型名: 1 var s1: enum<AA,BB> = $AA 2 var s2: enum<AA=10,BB=20> = $BB 3 var f1: enum<AA;BB;CC> = $AA + $BB 类似地,状态枚举和标识枚举的类型名的主要差异是使用逗号或分号。 这种枚举类型名在函数参数里使用非常方便。例如: 1 routine MySearch( values: list<int>, direction: enum<forward,backward> ) 2 { 3 ... 4 } 5 var values = { 1, 2, 3 } 6 var result = MySearch( values, $forward ) 0.6 Switch-Case里使用枚举类型 枚举类型可有效地用在Switch-Case里。 只要case项里的常量在编译时有确定(显式声明的或推导的)的 枚举类型, 这样的Switch-Case通常可以被优化为简单的跳转表。 例如: 1 switch( (any)e1 ){ 2 case MyEnum::AA : ... 3 case MyEnum::BB : ... 4 case MyEnum::CC : ... 5 } 6 7 switch( e1 ){ 8 case $AA : ... 9 case $BB : ... 10 case $CC : ... 11 } 这两个Switch-Case都将被优化为跳转表,因为前者的Case项都有明确的枚举类型。 而后者的则可通过变 量e的类型来推导出。 但下例则不能作此优化: 1 switch( (any)e1 ){ 2 case $AA : ... 3 case $BB : ... 4 case $CC : ... 5 } 因为switch()里的表达式没有明确的类型, Case项里的符号也没有明确的美剧类型。