列挙型
enum
は、名前付き定数値を定義できる機能である。
マジック定数がコードの品質に与える影響
次のコードは、整数と算術演算の章の演習問題の解答に載っていたものである。
そのコード内の整数リテラル1
、2
、3
、および4
は、マジック定数と呼ばれる。これらのリテラルがプログラム内で何を意味するかを判断するのは容易ではない。1
が加算を意味し、2
が減算を意味するなど、各スコープ内のコードを調べなければならない。上記のコードでは、すべてのスコープが1行のみのため、この作業は比較的簡単である。しかし、他のほとんどのプログラムでは、マジック定数の意味を解読するのははるかに困難だ。
マジック定数は、ソースコードの2つの重要な特性、すなわち可読性と保守性を損なうため、使用は避けるべきだ。
enum
このような定数に名前を付けることを可能にし、その結果、コードの読みやすさと保守性を向上させる。以下のenum
定数を使用すれば、各条件はすぐに理解できるだろう:
上記のenum
型Operation
は、マジック定数1
、2
、3
、および4
の必要性を排除し、次のように定義することができる。
enum
の構文
enum
の一般的な定義は次の通りだ:
値の実際の型 (基本型) も指定する必要がある場合がある。
これらがどのように使用されるかは、次のセクションで説明する。
TypeNameは、定数の集合が意味するところを定義する。enum
型のメンバー定数はすべて、中括弧で囲んで列挙する。以下に例を示す。
各定数のセットは、個別の型の一部になる。例えば、heads
およびtails
は、型HeadsOrTails
のメンバーになる。新しい型は、変数を定義する際に他の基本型と同様に使用できる。
上記のコードで見たように、enum
型のメンバーは、常にそのenum
型の名前で指定される。
実際の値と基本型
enum
型のメンバー定数は、デフォルトではint
型の値として実装される。つまり、表面的にはheads
やtails
のような名前で表示されるが、数値も持つ。(注釈:必要に応じて、int
以外の型を選択することも可能だ。)
プログラマが明示的に指定しない限り、enum
メンバーの数値は0
から始まり、メンバーごとに1ずつ増加する。例えば、HeadsOrTails
enum
の2つのメンバーの数値は0と1になる。
出力:
headsは0 | true |
---|---|
tailsは1 | true |
enum
の任意の場所で、値を手動で (再) 設定することができる。これは、上記でOperation.add
の値を1に指定した場合と同じだ。次の例では、新しいカウントを2回手動で設定している。
出力:
Test.b | Test.ç | Test.ğ |
---|---|---|
1 | 100 | 224 |
int
がenum
の値の基底型として適さない場合、enum
の名の後に基底型を明示的に指定することができる。
enum
enum
型ではない値
マジック定数を避け、代わりにenum
機能を利用することが重要であることを説明した。
しかし、名前付き定数を使用するためだけに、enum
型の名前を考えるのは不自然な場合もある。1日の秒数を表す名前付き定数が必要だとしよう。この定数値を含む enum
型も定義する必要はない。必要なのは、その名前で参照できる定数値だけだ。このような場合、enum
の型名と中括弧は省略する。
定数の型は明示的に指定することができる。これは、右辺から型を推測できない場合に必要である。
参照するenum
型がないため、このような名前付き定数は、その名前だけでコードで使用できる。
enum
は、他の型の名前付き定数を定義するためにも使用できる。例えば、次の定数の型はstring
になる。
このような定数はr値であり、明示定数と呼ばれる。
配列や連想配列の明示的定数も作成できる。ただし、後で不変性章で見るように、enum
の配列や連想配列には隠れたコストがある可能性がある。
プロパティ
.min
および.max
プロパティは、enum
型の最小値と最大値である。enum
型の値が連続している場合、これらの制限の範囲内で、for
ループで反復処理することができる。
フォーマット指定子 "%s"
と "%d"
は異なる出力を生成する:
spades | 0 |
---|---|
hearts | 1 |
diamonds | 2 |
clubs | 3 |
その範囲をループするforeach
では、.max
の値は反復処理から除外されることに注意。
出力:
spades: 0
hearts: 1
diamonds: 2
← clubsが欠落している
そのため、enum
のすべての値を反復する正しい方法は、std.traits
モジュールにあるEnumMembers
テンプレートを使うことだ。
注釈:上記の!
文字は、テンプレートのインスタンス化のために使用されている。これについては、後の章で説明する。
spades: 0
hearts: 1
diamonds: 2
clubs: 3 ← clubsが存在する
基本型からの変換
上記のフォーマットされた出力で見たように、enum
の値は、その基本型(int
など)に自動的に変換される。逆の変換は自動的には行われない。
その理由のひとつは、無効なenum
値になることを避けるためだ。
特定のenum
型の有効なenum
値に対応することがわかっている値は、明示的な型キャストによってその型に変換することができる。
明示的な型キャストを使用する場合、値の有効性を確認するのはプログラマーの責任だ。型キャストについては、後の章で説明する。
演習
整数と算術演算の章の演習問題の計算機プログラムを修正し、ユーザーがメニューから算術演算を選択できるようにしよう。
このプログラムは、少なくとも以下の点で以前のプログラムと異なるものにしよう:
- マジック定数ではなく、
enum
値を使用すること。 int
の代わりにdouble
を使用する。switch
を使用する。