プログラミングにおいて、データ型は非常に重要です。データ型を理解することで、プログラムを効率的に書き、バグを回避することができます。その中でも、列挙型は非常に便利なデータ型の1つです。
列挙型とは、あらかじめ定義された一連の値の中から1つを選ぶことができるデータ型です。これは、プログラマーが列挙された値以外の値を入力することを防止することができます。また、列挙型は、読みやすさや保守性を高めるためにも使用されます。
この節では、列挙型の基本的な概念や使い方、そして実際のプログラムでの活用方法について学びます。列挙型を理解することで、より洗練されたプログラムを書くことができるようになるでしょう。
__TOC__
プログラミングにおいて、データを扱う際には、そのデータがどのような種類のものかを明確にする必要があります。例えば、数字データ、文字列データ、真偽値データなど、それぞれに対して異なる演算や処理が必要になるためです。
列挙型とは、あらかじめ定義された複数の値の中から一つを選ぶことができるデータ型です。例えば、「曜日」を表す列挙型を定義する場合には、「月曜日」「火曜日」「水曜日」などのいずれかを選ぶことができます。列挙型は、プログラムの中で一定の値しか取らないことを保証するため、プログラムの品質向上やバグの減少につながります。
列挙型は、プログラミング言語によって定義方法が異なりますが、一般的には以下のような形式で定義します。
enum 列挙型名 {
  列挙子1,
  列挙子2,
  列挙子3,
  ...
}
ここで、「列挙型名」は定義する列挙型の名前を、「列挙子1」「列挙子2」「列挙子3」といったものは、列挙型が取りうる値を定義するものです。
例えば、以下のように「曜日」を表す列挙型を定義することができます（プログラミング言語はJava）。
enum DayOfWeek {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}
列挙型名は「DayOfWeek」とし、それぞれの列挙子には曜日の名前を設定しています。
列挙型を使用する際には、定義した列挙型の名前と列挙子を指定します。
例えば、上記の「DayOfWeek」列挙型を使用する場合には、以下のように記述します。
DayOfWeek today = Wednesday;
変数「today」には「Wednesday」という値が設定されます。
列挙型で定義された列挙値をswitchや類似の制御構造で網羅していな買った場合、コンパイラ等は静的に網羅性の担保を支援する事ができます。
Rust
Rustは、列挙型(enum)とマッチング(match)構文を組み合わせて、パターンマッチングを実現しています。これにより、全てのパターンを網羅するかどうかをコンパイル時に確認することができます。また、Rustには、コンパイル時に安全性をチェックするための静的解析ツールであるClippyがあり、列挙型のパターンマッチングにおいて未網羅のパターンを検出することができます。
// 列挙型（enum） Suitを定義
enum Suit {
    Heart, // ハートのスート
    Diamond, // ダイヤのスート
    Club, // クラブのスート
    Spade, // スペードのスート
}
// スートを出力する関数 print_cardを定義
fn print_card(suit: Suit) {
    // 引数で渡されたスートに応じてメッセージを出力
    match suit {
        Suit::Heart => println!("This is a heart."), // Heartの場合
        Suit::Diamond => println!("This is a diamond."), // Diamondの場合
        Suit::Club => println!("This is a club."), // Clubの場合
        Suit::Spade => println!("This is a spade."), // Spadeの場合
    }
}
// main関数で4つの異なるスートを出力する
fn main() {
    print_card(Suit::Heart); // ハートのスートを出力
    print_card(Suit::Diamond); // ダイヤのスートを出力
    print_card(Suit::Club); // クラブのスートを出力
    print_card(Suit::Spade); // スペードのスートを出力
}
Swift
Swiftは、列挙型(enum)とスイッチ(switch)文を組み合わせて、全てのケースを網羅していることをコンパイラが確認する機能を持っています。また、Swiftでは、列挙型に対して、コードの可読性を高めるためのエイリアスを定義することができます。
// スートの種類を定義するenum型
enum Suit {
    case heart
    case diamond
    case club
    case spade
}
// スートを受け取って、そのスートに応じてカードの種類を出力する関数
func printCard(suit: Suit) {
    switch suit {
    case .heart:
        print("This is a heart.")
    case .diamond:
        print("This is a diamond.")
    case .club:
        print("This is a club.")
    case .spade:
        print("This is a spade.")
    }
}
// カードの種類を出力する関数を、各スートで呼び出す
printCard(suit: .heart)
printCard(suit: .diamond)
printCard(suit: .club)
printCard(suit: .spade)
F#
F#は、列挙型(enum)とパターンマッチング(pattern matching)を組み合わせて、全てのパターンを網羅していることを確認する機能を持っています。また、F#では、列挙型に対して、マップやリストなどのデータ構造を組み合わせることができます。
// スートを表す列挙型を定義する
type Suit =
    | Heart      // ハート
    | Diamond    // ダイヤ
    | Club       // クラブ
    | Spade      // スペード
// スートに基づいてカードを印刷する関数を定義する
let printCard suit =
    match suit with
    | Heart -> printfn "This is a heart."   // ハートの場合
    | Diamond -> printfn "This is a diamond."   // ダイヤの場合
    | Club -> printfn "This is a club."     // クラブの場合
    | Spade -> printfn "This is a spade."   // スペードの場合
// カードを表示する
printCard Heart
printCard Diamond
printCard Club
printCard Spade
Kotlin
// トランプのカードのスートを表す列挙型
enum class Suit {
    HEART,    // ハート
    DIAMOND,  // ダイヤ
    CLUB,     // クラブ
    SPADE     // スペード
}
// スートに応じてカードを表示する関数
fun printCard(suit: Suit) {
    // スートに応じて処理を分岐
    when (suit) {
        Suit.HEART -> println("This is a heart.")    // ハートの場合
        Suit.DIAMOND -> println("This is a diamond.")// ダイヤの場合
        Suit.CLUB -> println("This is a club.")      // クラブの場合
        Suit.SPADE -> println("This is a spade.")    // スペードの場合
    }
}
fun main() {
    // カードを表示する
    printCard(Suit.HEART)    // ハートのカードを表示する
    printCard(Suit.DIAMOND)  // ダイヤのカードを表示する
    printCard(Suit.CLUB)     // クラブのカードを表示する
    printCard(Suit.SPADE)    // スペードのカードを表示する
}
Java
// 列挙型 Suit を定義する
enum Suit {
    HEART,    // ハート
    DIAMOND,  // ダイヤ
    CLUB,     // クラブ
    SPADE     // スペード
}
class Main {
    // printCard メソッドを定義する
    static void printCard(Suit suit) {
        // 引数で受け取った suit に応じて分岐する
        switch (suit) {
            case HEART:  // suit が HEART の場合
                // ハートであることを表示する
                System.out.println("This is a heart.");
                break;  // 分岐から抜ける
            case DIAMOND:  // suit が DIAMOND の場合
                // ダイヤであることを表示する
                System.out.println("This is a diamond.");
                break;  // 分岐から抜ける
            case CLUB:  // suit が CLUB の場合
                // クラブであることを表示する
                System.out.println("This is a club.");
                break;  // 分岐から抜ける
            case SPADE:  // suit が SPADE の場合
                // スペードであることを表示する
                System.out.println("This is a spade.");
                break;  // 分岐から抜ける
        }
    }
    // main メソッドを定義する
    public static void main(String[] args) {
        // printCard メソッドを呼び出して、それぞれのトランプのマークを表示する
        printCard(Suit.HEART);
        printCard(Suit.DIAMOND);
        printCard(Suit.CLUB);
        printCard(Suit.SPADE);
    }
}
Go
package main
import "fmt"
// 列挙型 Suit を定義
type Suit int
const (
    Heart Suit = iota // ハートのスート
    Diamond           // ダイヤのスート
    Club              // クラブのスート
    Spade             // スペードのスート
)
// スートを出力する関数 print_card を定義
func print_card(suit Suit) {
    // 引数で渡されたスートに応じてメッセージを出力
    switch suit {
    case Heart:
        fmt.Println("This is a heart.")
    case Diamond:
        fmt.Println("This is a diamond.")
    case Club:
        fmt.Println("This is a club.")
    case Spade:
        fmt.Println("This is a spade.")
    }
}
// main関数で4つの異なるスートを出力する
func main() {
    print_card(Heart)   // ハートのスートを出力
    print_card(Diamond) // ダイヤのスートを出力
    print_card(Club)    // クラブのスートを出力
    print_card(Spade)   // スペードのスートを出力
}
Scala
// 列挙型 Suit を定義
object Suit extends Enumeration {
  type Suit = Value
  val Heart, Diamond, Club, Spade = Value
}
// スートを出力する関数 print_card を定義
def print_card(suit: Suit.Suit): Unit = {
  // 引数で渡されたスートに応じてメッセージを出力
  suit match {
    case Suit.Heart   => println("This is a heart.")
    case Suit.Diamond => println("This is a diamond.")
    case Suit.Club    => println("This is a club.")
    case Suit.Spade   => println("This is a spade.")
  }
}
// main関数で4つの異なるスートを出力する
def main(args: Array[String]): Unit = {
  print_card(Suit.Heart)   // ハートのスートを出力
  print_card(Suit.Diamond) // ダイヤのスートを出力
  print_card(Suit.Club)    // クラブのスートを出力
  print_card(Suit.Spade)   // スペードのスートを出力
}
Haskell
-- 列挙型 Suit を定義
data Suit = Heart | Diamond | Club | Spade
    deriving (Show)
-- スートを出力する関数 print_card を定義
print_card :: Suit -> IO ()
print_card suit = case suit of
    Heart   -> putStrLn "This is a heart."
    Diamond -> putStrLn "This is a diamond."
    Club    -> putStrLn "This is a club."
    Spade   -> putStrLn "This is a spade."
-- main関数で4つの異なるスートを出力する
main :: IO ()
main = do
    print_card Heart   -- ハートのスートを出力
    print_card Diamond -- ダイヤのスートを出力
    print_card Club    -- クラブのスートを出力
    print_card Spade   -- スペードのスート
以上のように、これらのプログラミング言語では、列挙型を使った網羅性の担保を支援する機能が提供されています。
列挙型は、プログラミング言語やデーターベース管理システムにおいて、複数の異なる定数を1つの集合として定義したデーター型です。
古くは、Algol Hの言語定義に現れますが、辿ることが可能な初見の１つにPascalの（スカラー型から分岐した）列挙型が挙げられます。
[https://onlinegdb.com/f861aQs72 例]:
program EnumExample(output); 
type
  TSeassons = (Spring, Summer, Autumn, Winter);  
var
  seasson: TSeassons;
begin
  Writeln('seasson --> Ord(seasson)');
  Writeln('------------------------');
  for seasson := Spring to Winter do
    Writeln(seasson, ' --> ', Ord(seasson));
end. 
実行結果:
seasson --> Ord(seasson)
------------------------
Spring --> 0
Summer --> 1
Autumn --> 2
Winter --> 3
データ型（data type）：プログラム内で扱うデータの種類を表す型。
列挙型（enum）：あらかじめ定義された一連の値の中から1つを選ぶことができるデータ型。
プログラム（program）：コンピュータに実行させるための命令の集まり。
バグ（bug）：プログラムの実行中に発生するエラーのこと。
読みやすさ（readability）：コードが容易に理解できること。
保守性（maintainability）：プログラムが変更された場合に、容易に修正できること。
定義方法（definition）：列挙型を定義するための方法。
列挙子（enumerator）：列挙型が取りうる値を定義するもの。
Java：オブジェクト指向プログラミング言語の一種。
指定する（specify）：明確に示すこと。
網羅性（exhaustiveness）：全ての場合分けが正確に記述されていること。
静的に（statically）：コンパイル時に判断されること。
Rust：システムプログラミング言語の一種。
マッチング（matching）：値がどのパターンに合致するかを比較すること。
パターンマッチング（pattern matching）：値があるパターンに合致するかを判定し、適切な処理を行うこと。