列挙型(enum)
列挙体は有限個のコンストラクタを持った、クラスとは異なった構造です。以下に簡単な例を示します。
enum Color { Red; Green; Blue; } class Colors { static function toInt( c : Color ) : Int { return switch( c ) { case Red: 0xFF0000; case Green: 0x00FF00; case Blue: 0x0000FF; } } }
列挙体は指定されたコンストラクタ以外の値を取ることが出来ないので、それらに対する確実性を期待したい時に向いています。
Constructors parameters
上のColor列挙体のサンプルコードでは3つの定数コンストラクタが列挙体に与えられていました。
以下のようなパラメータを持ったコンストラクタも同様に扱うことができます。
enum Color2 { Red; Green; Blue; Grey( v : Int ); Rgb( r : Int, g : Int, b : Int ); }
この場合、Color2列挙体には無限のパターンがありますが、全ていずれかのコンストラクタに分類されることは変わりません。
以下に示す値は全てColor2列挙体となります。
Red;
Green;
Blue;
Grey(0);
Grey(128);
Rgb( 0x00, 0x12, 0x23 );
Rgb( 0xFF, 0xAA, 0xBB );
次のAlphaコンストラクタのように、再帰的なデータ型も与えることができます。
enum Color3 { Red; Green; Blue; Grey( v : Int ); Rgb( r : Int, g : Int, b : Int ); Alpha( a : Int, col : Color3 ); }
下の2つは共にColor3列挙体の値です。
Alpha( 127, Red ); Alpha( 255, Rgb(0,0,0) );
列挙体は不変なデータ型です。これは列挙体の値がリードオンリーであることを意味します。
すなわち、初期化した後に値を書き換えることはできません。
Switch on Enum
A switch has a special behavior when used on an enum. If there is no default case then it will check that all an enum's constructors are used within the switch, and if not the compiler will generate a warning. For example, consider the first Color enum :
switch( c ) { case Red: 0xFF0000; case Green: 0x00FF00; }
This will cause a compile errorwarning that the constructor blue is not used. In this example you can either add a case for it or add a default case that does something. This can be quite useful, as when you add new constructors to your enum, compiler errors will alert you to areas in your program where the new constructor should be handled.
Switch with Constructor Parameters
If enum constructor have parameters, they must be listed as variable names in a switch case. This way all the variables will be locally accessible in the case expression and correspond to the type of the enum constructor parameter. For example, using the Color3 enum:
class Colors { static function toInt( c : Color3 ) : Int { return switch( c ) { case Red: 0xFF0000; case Green: 0x00FF00; case Blue: 0x0000FF; case Grey(v): (v << 16) | (v << 8) | v; case Rgb(r,g,b): (r << 16) | (g << 8) | b; case Alpha(a,c): (a << 24) | (toInt(c) & 0xFFFFFF); } } }
Using switch is the only possible way to access the enum constructors parameters.
Enum Type Parameters
An Enum can also have type parameters. The syntax is the same so here's a small sample of a parameterized linked List using an enum to store the cells :
enum Cell<T> { Empty; Cons( item : T, next : Cell<T> ); } class List<T> { var head : Cell<T>; public function new() { head = Empty; } public function add( item : T ) { head = Cons(item,head); } public function length() : Int { return cellLength(head); } private function cellLength( c : Cell<T> ) : Int { return switch( c ) { case Empty : 0; case Cons(item,next): 1 + cellLength(next); } } }
Using both enums and classes together can be pretty powerful in some cases.
Using Enums as default value for parameters
Because an Enum's values are in fact created from a constructor they are not constant and therefore cannot be used as default value for a parameter. However there's a simple work-around :
enum MyEnum { MyFirstValue; MySecondValue; } class Test { static function withDefaultValuesOnParameters(?a : MyEnum) { if(a == null) a = MyEnum.MyFirstValue; } }
Enums to and from strings
Use Type.createEnum() method to recreate an enum value from a string:
enum EColor { Red; Green; Blue; } // To string: var string = Std.string(EColor.Blue); // From string: var color:EColor = Type.createEnum(EColor, string);
Enum Equality
Use Type.enumEq() to test for equality between two enums. (Operator == is not guaranteed, empirically will work for enum constructors that take no arguments, but can fail for those taking arguments. All of which can lead you astray: use Type.enumEq() to be correct.)
Note
Haxe Enums behave very similarly to tagged unions, enabling the specification and capture of every "case" of a given method result. Since all Enum states must be specified in switch statements, this makes them valuable in completely defining the behavior of a given method, as well as ensuring that these behaviors are handled.
«« 型パラメータ - Packages and Imports »»