列挙型
出典: フリー百科事典『ウィキペディア(Wikipedia)』
列挙型(れっきょがた、enumerated type)は、コンピュータプログラミングにおいて各々の値がプログラマが選んだ識別子のひとつひとつをそのまま有限のセットとして持つ抽象データ型である。列挙型は一般に番号順を持たないカテゴリ変数(ひとそろいのカードのように)として使われる。実行時に、列挙型は整数で実装される(各々の識別子はまったく異なる整数値を持つ)。
また、整数を使用して比較する列挙型は、明示的にマジックナンバーを使用するよりも、よりプログラムソースの可読性をよくするのに役立つ。言語に依存する整数表現はプログラマには不可視であることがある。これはプログラマに列挙値を算術演算のように使用する乱用を防ぐ。
言語によっては真偽値の論理型は、二つの値のあらかじめ宣言された列挙型と見なされる。
目次 |
[編集] Pascal
Pascalでは、列挙型は括弧で括られたリストで値を暗黙のうちに宣言できる:
var suit: (clubs, diamonds, hearts, spades);
宣言はしばしば、それが多重変数として使われるように型別名宣言に現れる:
type cardsuit = (clubs, diamonds, hearts, spades); card = record suit: cardsuit; value: 1 .. 13; end; var hand: array [ 1 .. 13 ] of card; trump: cardsuit;
列挙値の順序は書いた順番になる。列挙型は順序型 ordinal typeであり、prec、'succ関数は、列挙の前または次の値を与え、 ord は列挙値を整数表現に変換する。しかしながら、標準Pascalでは数値型から列挙型への変換を与えない。拡張されたPascalは拡張されたsucc関数経由でこの機能性を提供する。いくつかの他のPascal派生言語は型キャストを経由してそれを許可する。
[編集] Cと構文的にCに似ている言語
C言語のオリジナルのK&Rの派生言語は列挙型を持たなかったが、CにANSI標準には追加され、それはC89になった。Cでは、列挙は明示的にenumキーワードを宣言することで生成できる。それは構造体と共用体宣言をしのばせる:
enum cardsuit { CLUBS, DIAMONDS, HEARTS, SPADES }; struct card { enum cardsuit suit; short int value; } hand[13]; enum cardsuit trump;
Cは列挙値の小さな整数表現を直接プログラマに晒す。整数と列挙値は自由に混じり合う。列挙値における全ての数値演算は許可されている。列挙値にとって、列挙値のいくつかを表現しない整数を得ることはなおさら可能なことである。事実、言語仕様によると、上記のコードはint型の定数としてCLUBS
、DIAMONDS
、HEARTS
、SPADES
を定義しているが、もし、それらがその型の変数に保存されるときは、(黙って)enum cardsuit
に変換されるだけである。
Cはプログラマにはっきりと列挙定数の値を選ぶことも許可している。例えば、
enum cardsuit { CLUBS = 1, DIAMONDS = 2, HEARTS = 4, SPADES = 8 };
は、ビット演算によってenum cardsuit
として表現された一組の数学的な集合を許可する型を定義するために使われる。
Cの構文を受け継ぐ、型のない言語 (e.g. perl or JavaScript)は一般に列挙型をもたない。
[編集] C++
C++はCから直接引き継いだ列挙型を持ちっている。しかし列挙定数は、int型ではなく基の列挙型となる(ただしint型へ昇格できる)。このため整数型と列挙型との間で多重定義することができる。また、列挙型は利用者定義型の一種であるということから、列挙型に対しての演算子多重定義も可能となっている。
[編集] Java
JavaのJava SE(J2SE) version 5.0は宣言文法がCのそれに似ている列挙型を追加した:
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } ... Cardsuit trump ;
Javaの型システムは、整数から分離された型として列挙を扱うが、(.ordinal()
メソッドを使用してenum値の整数出力を取得できることを除き)enumと整数値との混合は許されていない。実際には、Javaのenum型は現に、数値型というよりもむしろ、コンパイラによって生成された特殊なクラスである。enum値はそのクラスのあらかじめ生成されたグローバルなインスタンスとして振る舞う。enum型はインスタンスメソッドとコンストラクタ(引数が各々のenum値を分割指定できる)を持つ。全てのenum型は暗黙のうちにEnum
抽象クラスを継承している。enum型を直接インスタンス化することは許可されない。
[編集] C#
C#プログラミング言語の列挙型はCのenumの意味する多くの"小さな整数"を保持する。いくつかの数値演算はenumでは定義されないが、enum値は明示的に整数に変換し元に戻すことができる。またenum変数はenum宣言によって定義されなかった値を保存できる。例として、
enum Cardsuit { Clubs, Diamonds, Spades, Hearts };
が与えられたとき、式Diamonds + 1
とHearts - Clubs
は直接許可される(なぜならば、一連の値を通して進めるかまたは、多くのものが二つの値間を渡る方法を尋ねることはことは理にかなっている)が、Hearts * Spades
は理に中っていないと考えられ、値が最初に整数に変換されるということだけが許可される。
[編集] VBA
VBAの列挙型は自動的に "整数"データ型に代入されし、それ自身データ型にもなりうる:
Option Explicit
Enum MyEnumeratedType
myType1 = 1
myType2 = -1
End Enum
Sub EnumExample()
Dim a As MyEnumeratedType
a = myType1
MsgBox a
End Sub
[編集] 関数型プログラミングにおける代数データ型
ML (プログラミング言語)の血統(e.g., SML、OCaml、Haskell)である関数型プログラミング言語ではnullary constructorしかない代数データ型は列挙型を実装するために使うことができる。例えば(SMLシグニチャの文法):
datatype cardsuit = Clubs | Diamonds | Hearts | Spades type card = { suit: cardsuit; value: int } val hand : card list val trump : cardsuit
もし、実際にそのような表現が実装に必要とされるならば、これらの言語では、小さな整数表現は完全にプログラマから隠蔽される。しかしながら、Haskellは型が派生でき、型とIntとのマッピングを得る実装ができるEnum 型クラスを持つ。
[編集] Lisp
Common Lispはメンバ型指定子を使用する, e.g.
(deftype cardsuit () '(member club diamond heart spade))
オブジェクトが、クラブ、ダイヤモンド、ハート、スペードへの#'eqlであるかどうかを一組のカードの型である状態。しかしメンバ型指定子はCLOS引数を特殊化するものとして妥当ではない。(eql atom)の替わりに、(member atom)が等価であるものが使われる(それは集合のメンバだけがeql型指定子で指定されるが、CLOS引数を特殊化するものとして使われるかも知れない。)。言い換えれば、 列挙型を覆うメソッドを定義するために、メソッドは各々の明確な型の要素を定義しなければならない。
その上、
(deftype finite-element-set-type (&rest elements) `(member ,@elements))
は実行時に任意の列挙型を定義するために使われるかも知れない。例えば
(finite-element-set-type club diamond heart spade)
は、確かに単純に使われるものとして一組のカードの優先する定義への型等価を参照する。
(member club diamond heart spade)
しかし、文体論上、関数#'memberの混乱は少ない。
[編集] データベース
データベースによっては列挙型を直接サポートする。 MySQLは テーブルが生成されるときの文字列として指定された許容量を持つ列挙型ENUMを提供する。0としての空文字列とともに値は数値インデックスとして保存される。最初の文字列には1が保存され、第二の文字列には2が保存される、etc..。値は数値インデックスまたは文字列として検索し保存することができる。