「列挙型」の版間の差分
編集の要約なし |
|||
10行目: | 10行目: | ||
=== Pascal === |
=== Pascal === |
||
[[Pascal]]では、列挙型は括弧で括られたリストで値を暗黙のうちに宣言できる。 |
[[Pascal]]では、列挙型は括弧で括られたリストで値を暗黙のうちに宣言できる。 |
||
< |
<syntaxhighlight lang="pascal"> |
||
var |
var |
||
suit: (clubs, diamonds, hearts, spades); |
suit: (clubs, diamonds, hearts, spades); |
||
</syntaxhighlight> |
|||
</source> |
|||
宣言は、それが多重変数として使われるように型別名宣言によく現れる。 |
宣言は、それが多重変数として使われるように型別名宣言によく現れる。 |
||
< |
<syntaxhighlight lang="pascal"> |
||
type |
type |
||
cardsuit = (clubs, diamonds, hearts, spades); |
cardsuit = (clubs, diamonds, hearts, spades); |
||
25行目: | 25行目: | ||
hand: array [ 1 .. 13 ] of card; |
hand: array [ 1 .. 13 ] of card; |
||
trump: cardsuit; |
trump: cardsuit; |
||
</syntaxhighlight> |
|||
</source> |
|||
列挙値の順序は書いた順番になる。列挙型は順序型 ''{{lang|en|ordinal type}}'' であり、<code>Pred</code>、<code>Succ</code>関数は、列挙の前または次の値を与え、 <code>Ord</code>は列挙値を整数表現に変換する。しかし、標準Pascalでは数値型から列挙型への変換はできない。拡張Pascalは拡張された<code>Succ</code>関数経由でこの機能性を提供する。他のPascal派生言語の一部では、型キャストで変換可能なものもある。 |
列挙値の順序は書いた順番になる。列挙型は順序型 ''{{lang|en|ordinal type}}'' であり、<code>Pred</code>、<code>Succ</code>関数は、列挙の前または次の値を与え、 <code>Ord</code>は列挙値を整数表現に変換する。しかし、標準Pascalでは数値型から列挙型への変換はできない。拡張Pascalは拡張された<code>Succ</code>関数経由でこの機能性を提供する。他のPascal派生言語の一部では、型キャストで変換可能なものもある。 |
||
=== Ada === |
=== Ada === |
||
Adaでは、Pascalとよく似た定義となるが"="の替りに"is"を用いる。 |
Adaでは、Pascalとよく似た定義となるが"="の替りに"is"を用いる。 |
||
< |
<syntaxhighlight lang="ada"> |
||
type Cardsuit is (Clubs, Diamonds, Hearts, Spades); |
type Cardsuit is (Clubs, Diamonds, Hearts, Spades); |
||
</syntaxhighlight> |
|||
</source> |
|||
属性Pred, Succ, ValおよびPosに加えて、Adaには更に属性ImageおよびValueがあり、文字列変換を行うことができる(Image: 列挙値から文字列への変換、Value: 文字列から列挙値への変換)。 |
属性Pred, Succ, ValおよびPosに加えて、Adaには更に属性ImageおよびValueがあり、文字列変換を行うことができる(Image: 列挙値から文字列への変換、Value: 文字列から列挙値への変換)。 |
||
Cスタイルの言語と同様に、Adaでは列挙値として数値に何を用いるかを指定することができる。 |
Cスタイルの言語と同様に、Adaでは列挙値として数値に何を用いるかを指定することができる。 |
||
< |
<syntaxhighlight lang="ada"> |
||
for Cardsuit use (Clubs => 1, Diamonds => 2, Hearts => 4, Spades => 8); |
for Cardsuit use (Clubs => 1, Diamonds => 2, Hearts => 4, Spades => 8); |
||
</syntaxhighlight> |
|||
</source> |
|||
Cスタイルの言語と異なり、Adaでは列挙値に割り当てるビット数を指定することができる。 |
Cスタイルの言語と異なり、Adaでは列挙値に割り当てるビット数を指定することができる。 |
||
< |
<syntaxhighlight lang="ada"> |
||
for Cardsuit'Size use 4; -- 4 ビット |
for Cardsuit'Size use 4; -- 4 ビット |
||
</syntaxhighlight> |
|||
</source> |
|||
さらに列挙値を配列の添字として用いることもできる。 |
さらに列挙値を配列の添字として用いることもできる。 |
||
< |
<syntaxhighlight lang="ada"> |
||
Shuffle : constant array(Cardsuit) of Cardsuit := |
Shuffle : constant array(Cardsuit) of Cardsuit := |
||
(Clubs => Cardsuit'Succ(Clubs), -- Clubsの"次の値"を指定: Diamondsになる |
(Clubs => Cardsuit'Succ(Clubs), -- Clubsの"次の値"を指定: Diamondsになる |
||
51行目: | 51行目: | ||
Spades => Cardsuit'First -- 列挙型の"最初の値"を指定: Clubsになる |
Spades => Cardsuit'First -- 列挙型の"最初の値"を指定: Clubsになる |
||
); |
); |
||
</syntaxhighlight> |
|||
</source> |
|||
[[Modula-3]]と同様に、AdaではBooleanやCharacterは列挙型の一種に過ぎない(パッケージ"Standard"で既定義)。Modula-3と異なり、Adaでは自前の文字型も定義することができる。 |
[[Modula-3]]と同様に、AdaではBooleanやCharacterは列挙型の一種に過ぎない(パッケージ"Standard"で既定義)。Modula-3と異なり、Adaでは自前の文字型も定義することができる。 |
||
< |
<syntaxhighlight lang="ada"> |
||
type Cards is ("7", "8", "9", "J", "Q", "K", "A"); |
type Cards is ("7", "8", "9", "J", "Q", "K", "A"); |
||
</syntaxhighlight> |
|||
</source> |
|||
== Cおよび構文的に類似の言語 == |
== Cおよび構文的に類似の言語 == |
||
=== C言語 === |
=== C言語 === |
||
[[C言語]]のオリジナルの[[C言語#K&R|K&R]]に列挙型は存在しなかったが、[[ANSI]]標準 (C89) で追加された。Cでは、列挙は明示的に'''enum'''キーワードを宣言することで生成できる。それは[[構造体]]と[[共用体]]宣言を連想させる。 |
[[C言語]]のオリジナルの[[C言語#K&R|K&R]]に列挙型は存在しなかったが、[[ANSI]]標準 (C89) で追加された。Cでは、列挙は明示的に'''enum'''キーワードを宣言することで生成できる。それは[[構造体]]と[[共用体]]宣言を連想させる。 |
||
< |
<syntaxhighlight lang="c"> |
||
enum cardsuit { |
enum cardsuit { |
||
CLUBS, |
CLUBS, |
||
75行目: | 75行目: | ||
enum cardsuit trump; |
enum cardsuit trump; |
||
</syntaxhighlight> |
|||
</source> |
|||
Cは列挙値の"小さな整数"<!-- おそらく、intで表現可能な範囲という意味で「小さい」という言葉が使われているものと思われる。 -->表現を直接プログラマに公開する。整数と列挙値は自由に変換可能であり、列挙値でも全ての数値演算が可能となっている。結果として、列挙体に定義されていない値すら取りえることもある。事実、言語仕様によると、上記のコードは'''int'''型の定数として<code>CLUBS</code>、<code>DIAMONDS</code>、<code>HEARTS</code>、<code>SPADES</code>を定義しているが、これらがその型の変数に保存されるときは、(暗黙裡に)<code>enum cardsuit</code>に変換されるだけである。 |
Cは列挙値の"小さな整数"<!-- おそらく、intで表現可能な範囲という意味で「小さい」という言葉が使われているものと思われる。 -->表現を直接プログラマに公開する。整数と列挙値は自由に変換可能であり、列挙値でも全ての数値演算が可能となっている。結果として、列挙体に定義されていない値すら取りえることもある。事実、言語仕様によると、上記のコードは'''int'''型の定数として<code>CLUBS</code>、<code>DIAMONDS</code>、<code>HEARTS</code>、<code>SPADES</code>を定義しているが、これらがその型の変数に保存されるときは、(暗黙裡に)<code>enum cardsuit</code>に変換されるだけである。 |
||
[[typedef]]によりエイリアスを定義することも可能である。 |
[[typedef]]によりエイリアスを定義することも可能である。 |
||
< |
<syntaxhighlight lang="c"> |
||
typedef enum cardsuit cardsuit_t; |
typedef enum cardsuit cardsuit_t; |
||
int a = DIAMONDS; |
int a = DIAMONDS; |
||
cardsuit_t b = DIAMONDS; |
cardsuit_t b = DIAMONDS; |
||
cardsuit_t c = 1; |
cardsuit_t c = 1; |
||
</syntaxhighlight> |
|||
</source> |
|||
Cでは、プログラマが明示的に列挙定数の値を指定することも可能である。例えば、 |
Cでは、プログラマが明示的に列挙定数の値を指定することも可能である。例えば、 |
||
< |
<syntaxhighlight lang="c"> |
||
enum cardsuit { |
enum cardsuit { |
||
CLUBS = 1, |
CLUBS = 1, |
||
94行目: | 94行目: | ||
SPADES = 8 |
SPADES = 8 |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
は、スートの数学的な集合をビット演算によって<code>enum cardsuit</code>として表現することを可能にする型を定義する目的で使える。<!-- 原文は「could be used to define a type that allows mathematical sets of suits to be represented as an enum cardsuit by bitwise logic operations.」だが、翻訳の際に2つの受動態をともに能動態に入れ替えている。 --> |
は、スートの数学的な集合をビット演算によって<code>enum cardsuit</code>として表現することを可能にする型を定義する目的で使える。<!-- 原文は「could be used to define a type that allows mathematical sets of suits to be represented as an enum cardsuit by bitwise logic operations.」だが、翻訳の際に2つの受動態をともに能動態に入れ替えている。 --> |
||
型名を持たない無名の列挙体を定義することも可能である。 |
型名を持たない無名の列挙体を定義することも可能である。 |
||
< |
<syntaxhighlight lang="c"> |
||
enum { |
enum { |
||
CLUBS, |
CLUBS, |
||
105行目: | 105行目: | ||
SPADES |
SPADES |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
Cの構文を受け継ぐが型のない言語([[Perl]]や[[JavaScript]]など)は一般に列挙型をもたない。 |
Cの構文を受け継ぐが型のない言語([[Perl]]や[[JavaScript]]など)は一般に列挙型をもたない。 |
||
113行目: | 113行目: | ||
[[C++11]]では、スコープ付きの強く型付けされた列挙型(enum classもしくはenum struct)が新たに実装された。 |
[[C++11]]では、スコープ付きの強く型付けされた列挙型(enum classもしくはenum struct)が新たに実装された。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts }; |
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts }; |
||
int a = Cardsuit::Hearts; // コンパイルエラー。 |
int a = Cardsuit::Hearts; // コンパイルエラー。 |
||
Cardsuit b = Cardsuit::Hearts; |
Cardsuit b = Cardsuit::Hearts; |
||
</syntaxhighlight> |
|||
</source> |
|||
=== C# === |
=== C# === |
||
[[C Sharp|C#]]の列挙型は<code>System.Enum</code>から暗黙的に派生する値型であり、Cのenumの意味する多くの"小さな整数"を保持する。いくつかの数値演算はenumでは定義されないが、enum値は明示的に整数値に型変換することができ、また整数値から元に戻すこともできる。またenum変数はenum宣言によって定義されなかった値を保存できる。例として、 |
[[C Sharp|C#]]の列挙型は<code>System.Enum</code>から暗黙的に派生する値型であり、Cのenumの意味する多くの"小さな整数"を保持する。いくつかの数値演算はenumでは定義されないが、enum値は明示的に整数値に型変換することができ、また整数値から元に戻すこともできる。またenum変数はenum宣言によって定義されなかった値を保存できる。例として、 |
||
< |
<syntaxhighlight lang="csharp"> |
||
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
||
</syntaxhighlight> |
|||
</source> |
|||
が与えられたとき、式<code>Diamonds + 1</code>と<code>Hearts - Clubs</code>は直接許可される(ループで一連の値を走査することや、二つのenumの間にいくつのステップがあるか計算することはありうる)が、<code>Hearts * Spades</code>は理にかなっていないと考えられ、値が最初に整数に変換されるということだけが許可される。 |
が与えられたとき、式<code>Diamonds + 1</code>と<code>Hearts - Clubs</code>は直接許可される(ループで一連の値を走査することや、二つのenumの間にいくつのステップがあるか計算することはありうる)が、<code>Hearts * Spades</code>は理にかなっていないと考えられ、値が最初に整数に変換されるということだけが許可される。 |
||
また、<code>FlagsAttribute</code>を指定することで、ビット演算が許可される。 |
また、<code>FlagsAttribute</code>を指定することで、ビット演算が許可される。 |
||
< |
<syntaxhighlight lang="csharp"> |
||
/// <summary>光の三原色を1bitずつで表す</summary> |
/// <summary>光の三原色を1bitずつで表す</summary> |
||
[Flags] |
[Flags] |
||
137行目: | 137行目: | ||
White = Red | Green | Blue, |
White = Red | Green | Blue, |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Groovy === |
=== Groovy === |
||
< |
<syntaxhighlight lang="java"> |
||
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Java === |
=== Java === |
||
[[Java]]は[[Java Platform, Standard Edition|Java SE]] (J2SE) version 5.0から列挙型を導入した。 |
[[Java]]は[[Java Platform, Standard Edition|Java SE]] (J2SE) version 5.0から列挙型を導入した。 |
||
< |
<syntaxhighlight lang="java"> |
||
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
enum Cardsuit { Clubs, Diamonds, Spades, Hearts } |
||
... |
... |
||
Cardsuit trump; |
Cardsuit trump; |
||
</syntaxhighlight> |
|||
</source> |
|||
Javaの型システムは、整数から分離された型として列挙を扱うが、(<code>ordinal()</code>メソッドを使用してenum値の整数表現を取得できることを除き)enumと整数値との混合演算は許されていない。実際には、Javaのenum型は現に、数値型というよりもむしろ、コンパイラによって生成された特殊な[[クラス (コンピュータ)|クラス]]である。enum値はそのクラスのあらかじめ生成されたグローバルなインスタンスとして振る舞う。enum型はインスタンスメソッドとコンストラクタ(引数が各々のenum値を分割指定できる)を持つ。全てのenum型は暗黙のうちに{{Javadoc:SE|java/lang|Enum}}[[抽象クラス]]を継承している。enum型を直接インスタンス化することは許可されない。 |
Javaの型システムは、整数から分離された型として列挙を扱うが、(<code>ordinal()</code>メソッドを使用してenum値の整数表現を取得できることを除き)enumと整数値との混合演算は許されていない。実際には、Javaのenum型は現に、数値型というよりもむしろ、コンパイラによって生成された特殊な[[クラス (コンピュータ)|クラス]]である。enum値はそのクラスのあらかじめ生成されたグローバルなインスタンスとして振る舞う。enum型はインスタンスメソッドとコンストラクタ(引数が各々のenum値を分割指定できる)を持つ。全てのenum型は暗黙のうちに{{Javadoc:SE|java/lang|Enum}}[[抽象クラス]]を継承している。enum型を直接インスタンス化することは許可されない。 |
||
=== Kotlin === |
=== Kotlin === |
||
< |
<syntaxhighlight lang="java"> |
||
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts } |
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts } |
||
</syntaxhighlight> |
|||
</source> |
|||
=== TypeScript === |
=== TypeScript === |
||
< |
<syntaxhighlight lang="java"> |
||
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }; |
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }; |
||
</syntaxhighlight> |
|||
</source> |
|||
== その他の手続き型言語 == |
== その他の手続き型言語 == |
||
203行目: | 203行目: | ||
=== VBA === |
=== VBA === |
||
VBAの列挙型は自動的に"整数"データ型に代入され、それ自身データ型にもなりうる。 |
VBAの列挙型は自動的に"整数"データ型に代入され、それ自身データ型にもなりうる。 |
||
< |
<syntaxhighlight lang="vb"> |
||
Option Explicit |
Option Explicit |
||
216行目: | 216行目: | ||
MsgBox a |
MsgBox a |
||
End Sub |
End Sub |
||
</syntaxhighlight> |
|||
</source> |
|||
== 関数型言語 == |
== 関数型言語 == |
||
=== Common Lisp === |
=== Common Lisp === |
||
[[Common Lisp]]は、型指定子 member を用いる。例えば、 |
[[Common Lisp]]は、型指定子 member を用いる。例えば、 |
||
< |
<syntaxhighlight lang="lisp"> |
||
(deftype cardsuit () |
(deftype cardsuit () |
||
'(member club diamond heart spade)) |
'(member club diamond heart spade)) |
||
</syntaxhighlight> |
|||
</source> |
|||
ここで定義された cardsuit型 は、シンボルclub、diamond、heart、spadeの集合となる。 |
ここで定義された cardsuit型 は、シンボルclub、diamond、heart、spadeの集合となる。 |
||
< |
<syntaxhighlight lang="lisp"> |
||
(typep 'club 'cardsuit) ;clubは、cardsuit型か? |
(typep 'club 'cardsuit) ;clubは、cardsuit型か? |
||
;=> T ;true |
;=> T ;true |
||
</syntaxhighlight> |
|||
</source> |
|||
また、上記の型定義で利用した deftype は、表記を拡張することにも用いる。 |
また、上記の型定義で利用した deftype は、表記を拡張することにも用いる。 |
||
< |
<syntaxhighlight lang="lisp"> |
||
(deftype finite-element-set-type (&rest elements) |
(deftype finite-element-set-type (&rest elements) |
||
`(member ,@elements)) |
`(member ,@elements)) |
||
</syntaxhighlight> |
|||
</source> |
|||
は、型指定子 member に finite-element-set-type という新しい名前を付ける。 |
は、型指定子 member に finite-element-set-type という新しい名前を付ける。 |
||
これを用いて、 |
これを用いて、 |
||
< |
<syntaxhighlight lang="lisp"> |
||
(deftype cardsuit () |
(deftype cardsuit () |
||
'(finite-element-set-type club diamond heart spade)) |
'(finite-element-set-type club diamond heart spade)) |
||
</syntaxhighlight> |
|||
</source> |
|||
として、前述のcardsuitと同じものを定義することに利用できる。表記上似ていて紛らわしいmember関数との混同を避けることに使えるだろう。 |
として、前述のcardsuitと同じものを定義することに利用できる。表記上似ていて紛らわしいmember関数との混同を避けることに使えるだろう。 |
||
なお、CLOSの引数特定子には、型指定子memberに相当するものはないため、メソッドの定義 (defmethod) で同様のことを実現する場合は、メンバー個々をeql特定子を用いて定義する必要があるだろう。 |
なお、CLOSの引数特定子には、型指定子memberに相当するものはないため、メソッドの定義 (defmethod) で同様のことを実現する場合は、メンバー個々をeql特定子を用いて定義する必要があるだろう。 |
2020年7月5日 (日) 22:50時点における版
列挙型(れっきょがた、enumerated typeあるいはenumeration type)とは、コンピュータプログラミングにおいて、プログラマが選んだ各々の識別子(列挙子)をそのまま有限集合として持つ抽象データ型である。列挙型は一般に、カードのスートのように番号順を持たないカテゴリ変数として使われるが、実際のコンパイル時あるいは実行時には、列挙型は整数で実装されることが多い。各々の識別子は通例異なる整数値を持つが、複数の識別子に対して意図的に同じ整数値を割り当てる(つまり別名を定義する)ことも可能である。
また列挙型は、整数を使用する場合と比較して、明示的にマジックナンバーを使用するよりもプログラムソースの可読性を改善するのに役立つ。言語によっては、列挙型の整数表現はプログラマに見えないようになっていることもあり、これによりプログラマが列挙値に対して算術演算を行うような乱用を防いでいる。
プログラミング言語によっては、真偽値の論理型は、あらかじめ宣言された二値の列挙型とされている。
C言語では構造体および共用体のアナロジーとして、列挙体(enumeration)とも呼ばれる。
Pascalおよび類似言語
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 であり、Pred
、Succ
関数は、列挙の前または次の値を与え、 Ord
は列挙値を整数表現に変換する。しかし、標準Pascalでは数値型から列挙型への変換はできない。拡張Pascalは拡張されたSucc
関数経由でこの機能性を提供する。他のPascal派生言語の一部では、型キャストで変換可能なものもある。
Ada
Adaでは、Pascalとよく似た定義となるが"="の替りに"is"を用いる。
type Cardsuit is (Clubs, Diamonds, Hearts, Spades);
属性Pred, Succ, ValおよびPosに加えて、Adaには更に属性ImageおよびValueがあり、文字列変換を行うことができる(Image: 列挙値から文字列への変換、Value: 文字列から列挙値への変換)。
Cスタイルの言語と同様に、Adaでは列挙値として数値に何を用いるかを指定することができる。
for Cardsuit use (Clubs => 1, Diamonds => 2, Hearts => 4, Spades => 8);
Cスタイルの言語と異なり、Adaでは列挙値に割り当てるビット数を指定することができる。
for Cardsuit'Size use 4; -- 4 ビット
さらに列挙値を配列の添字として用いることもできる。
Shuffle : constant array(Cardsuit) of Cardsuit :=
(Clubs => Cardsuit'Succ(Clubs), -- Clubsの"次の値"を指定: Diamondsになる
Diamonds => Hearts, -- 列挙リテラル: 直接Heartsを指定
Hearts => Cardsuit'Last, -- 列挙型の"最後の値"を指定: Spadesになる
Spades => Cardsuit'First -- 列挙型の"最初の値"を指定: Clubsになる
);
Modula-3と同様に、AdaではBooleanやCharacterは列挙型の一種に過ぎない(パッケージ"Standard"で既定義)。Modula-3と異なり、Adaでは自前の文字型も定義することができる。
type Cards is ("7", "8", "9", "J", "Q", "K", "A");
Cおよび構文的に類似の言語
C言語
C言語のオリジナルのK&Rに列挙型は存在しなかったが、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
に変換されるだけである。
typedefによりエイリアスを定義することも可能である。
typedef enum cardsuit cardsuit_t;
int a = DIAMONDS;
cardsuit_t b = DIAMONDS;
cardsuit_t c = 1;
Cでは、プログラマが明示的に列挙定数の値を指定することも可能である。例えば、
enum cardsuit {
CLUBS = 1,
DIAMONDS = 2,
HEARTS = 4,
SPADES = 8
};
は、スートの数学的な集合をビット演算によってenum cardsuit
として表現することを可能にする型を定義する目的で使える。
型名を持たない無名の列挙体を定義することも可能である。
enum {
CLUBS,
DIAMONDS,
HEARTS,
SPADES
};
Cの構文を受け継ぐが型のない言語(PerlやJavaScriptなど)は一般に列挙型をもたない。
C++
C++はCから直接引き継いだ列挙型を持っている。しかし列挙定数は、int型ではなく基の列挙型となる(ただしint型へ昇格できる。整数から列挙型への変換には明示的なキャストが必要である)。このため、整数型と列挙型との間で多重定義できる。また、列挙型は利用者定義型の一種であるということから、列挙型に対しての演算子多重定義も可能となっている。
C++11では、スコープ付きの強く型付けされた列挙型(enum classもしくはenum struct)が新たに実装された。
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts };
int a = Cardsuit::Hearts; // コンパイルエラー。
Cardsuit b = Cardsuit::Hearts;
C#
C#の列挙型はSystem.Enum
から暗黙的に派生する値型であり、Cのenumの意味する多くの"小さな整数"を保持する。いくつかの数値演算はenumでは定義されないが、enum値は明示的に整数値に型変換することができ、また整数値から元に戻すこともできる。またenum変数はenum宣言によって定義されなかった値を保存できる。例として、
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }
が与えられたとき、式Diamonds + 1
とHearts - Clubs
は直接許可される(ループで一連の値を走査することや、二つのenumの間にいくつのステップがあるか計算することはありうる)が、Hearts * Spades
は理にかなっていないと考えられ、値が最初に整数に変換されるということだけが許可される。
また、FlagsAttribute
を指定することで、ビット演算が許可される。
/// <summary>光の三原色を1bitずつで表す</summary>
[Flags]
enum RgbColor : byte {
Black = 0, Red = 1, Green = 2, Blue = 4,
Cyan = Green | Blue,
Magenta = Blue | Red,
Yellow = Red | Green,
White = Red | Green | Blue,
}
Groovy
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }
Java
JavaはJava SE (J2SE) version 5.0から列挙型を導入した。
enum Cardsuit { Clubs, Diamonds, Spades, Hearts }
...
Cardsuit trump;
Javaの型システムは、整数から分離された型として列挙を扱うが、(ordinal()
メソッドを使用してenum値の整数表現を取得できることを除き)enumと整数値との混合演算は許されていない。実際には、Javaのenum型は現に、数値型というよりもむしろ、コンパイラによって生成された特殊なクラスである。enum値はそのクラスのあらかじめ生成されたグローバルなインスタンスとして振る舞う。enum型はインスタンスメソッドとコンストラクタ(引数が各々のenum値を分割指定できる)を持つ。全てのenum型は暗黙のうちにEnum
抽象クラスを継承している。enum型を直接インスタンス化することは許可されない。
Kotlin
enum class Cardsuit { Clubs, Diamonds, Spades, Hearts }
TypeScript
enum Cardsuit { Clubs, Diamonds, Spades, Hearts };
その他の手続き型言語
Fortran
enum, bind( C )
enumerator :: CLUBS = 1, DIAMONDS = 2, HEARTS = 4, SPADES = 8
end enum
Perl
my @enum = qw(CLUBS DIAMONDS HEARTS SPADES);
my( %set1, %set2 );
@set1{@enum} = (); # all cleared
@set2{@enum} = (1) x @enum; # all set to 1
$set1{CLUBS} ... # false
$set2{DIAMONDS} ... # true
Python
from enum import Enum
class Cardsuit(Enum):
clubs = 1
diamonds = 2
hearts = 3
spades = 4
Ruby
module Cardsuit
clubs = 1
diamonds = 2
hearts = 3
spades = 4
end
VBA
VBAの列挙型は自動的に"整数"データ型に代入され、それ自身データ型にもなりうる。
Option Explicit
Enum MyEnumeratedType
myType1 = 1
myType2 = -1
End Enum
Sub EnumExample()
Dim a As MyEnumeratedType
a = myType1
MsgBox a
End Sub
関数型言語
Common Lisp
Common Lispは、型指定子 member を用いる。例えば、
(deftype cardsuit ()
'(member club diamond heart spade))
ここで定義された cardsuit型 は、シンボルclub、diamond、heart、spadeの集合となる。
(typep 'club 'cardsuit) ;clubは、cardsuit型か?
;=> T ;true
また、上記の型定義で利用した deftype は、表記を拡張することにも用いる。
(deftype finite-element-set-type (&rest elements)
`(member ,@elements))
は、型指定子 member に finite-element-set-type という新しい名前を付ける。 これを用いて、
(deftype cardsuit ()
'(finite-element-set-type club diamond heart spade))
として、前述のcardsuitと同じものを定義することに利用できる。表記上似ていて紛らわしいmember関数との混同を避けることに使えるだろう。 なお、CLOSの引数特定子には、型指定子memberに相当するものはないため、メソッドの定義 (defmethod) で同様のことを実現する場合は、メンバー個々をeql特定子を用いて定義する必要があるだろう。
ML
MLの血統 (例えば、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型クラスを持つ。
Scala
object Cardsuit extends Enumeration {
type Cardsuit = Value
val Clubs, Diamonds, Spades, Hearts = Value
}
データベース
データベースによっては列挙型を直接サポートする。
MySQL
MySQLでは、テーブルが生成されるときの文字列として指定された許容量を持つ列挙型ENUMが存在する。0としての空文字列とともに値は数値インデックスとして保存される。最初の文字列には1が保存され、第二の文字列には2が保存される、etc...。値は数値インデックスまたは文字列として検索し保存することができる。
PostgreSQL
PostgreSQLでは CREATE ENUM 構文にて列挙型を定義できる。入出力は文字列として行うが、内部的にはシステムが割り当てた 4 byte の整数として保存される。列挙型の名前が長い場合には格納の効率が高まり、数値として処理できるため検索性能も向上する。