列挙型

一、列挙型(Enumerated Type)

Pascalの列挙型はカプセル化に優れた不透明型で、実務開発では他言語の列挙型より頻繁に使用されます。

基本的な定義記法

type
  TAnimalKind = (akDuck, akCat, akDog);

コーディング規約:列挙定数名に型名2文字略称のプレフィックスを付ける

  • ak = Animal Kind(TAnimalKindの略称)
  • 役割:列挙定数は既定でユニットのグローバル名前空間に属するため、プレフィックスを付けることで他変数・型との名前衝突を大幅に抑えられます。

TAnimalKindの先頭Tは構文上省略可能ですが、業界標準の規則のため付記を推奨します。一目で列挙型と判断できるようになります。

type
  AnimalKind = (akDuck, akCat, akDog); // Tなしでも構文的に有効Code language: JavaScript (javascript)

補足情報:

  1. 同名の識別子が存在しても即時コンパイルエラーにはならず、別ユニットに同一名を定義可能;
  2. ただしコード可読性・全体検索(grep)の利便性のため、積極的に名前衝突を回避することが望ましいです。

スコープ付き列挙(限定列挙、{$scopedenums on})

コンパイラディレクティブ {$scopedenums on} を記述すると、列挙定数を型内部に隔離し、グローバル名前空間を汚染しなくなります

既定では無効
{$ifdef FPC} {$mode objfpc} {$H+} {$endif}
{$codepage utf8}
program EnumDemo;

type TAnimalKind = (akDuck, akCat);

var k: TAnimalKind;

begin
  k := akDuck; // TAnimalKind. なしで定数を直接記述可能
  WriteLn(k); //出力:akDuck
end.Code language: PHP (php)

先ほど説明した通り、このコードはbeginから実行が始まります。

akプレフィックスを付けると衝突回避に有利ですが、省略してもコンパイルエラーは発生しません。

{$ifdef FPC} {$mode objfpc} {$H+} {$endif}
{$codepage utf8}

program EnumDemo;

type TAnimalKind = (Duck, Cat);

var k: TAnimalKind;

begin
  k := Duck; 
  WriteLn(k);//Duck
end.Code language: PHP (php)

{$scopedenums on} 有効時は「型名.」の記述が必須

  1. 参照時に型名による修飾が必須:TAnimalKind.akDuck
  2. akプレフィックスは不要となり、定数をDuck、Cat、Dogと簡略記述できる
{$scopedenums on}
type
  TAnimalKind = (Duck, Cat, Dog);
var
  Kind: TAnimalKind;
begin
  Kind := TAnimalKind.Duck; // 型による修飾が必須
end;Code language: PHP (php)

型修飾を省略した場合

{$ifdef FPC} {$mode objfpc} {$H+} {$endif}
{$codepage utf8}
{$scopedenums on}
program EnumDemo;

type TAnimalKind = (Duck, Cat);
var k: TAnimalKind;
begin
  k := Duck; // TAnimalKind. による修飾が欠けている
  WriteLn(k);
end.Code language: PHP (php)

コンパイルエラーが出力されます

D:\fpcdemo>fpc mydemo.dpr
Free Pascal Compiler version 3.2.2 [2021/05/15] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling mydemo.dpr
mydemo.dpr(9,8) Error: Identifier not found "Duck"
mydemo.dpr(11,4) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: C:\FPC\3.2.2\bin\i386-Win32\ppc386.exe returned an error exitcodeCode language: CSS (css)

型修飾を追加すると

{$ifdef FPC} {$mode objfpc} {$H+} {$endif}
{$codepage utf8}
{$scopedenums on}
program EnumDemo;

type TAnimalKind = (Duck, Cat);
var k: TAnimalKind;
begin
  k := TAnimalKind.Duck; // 完全な型修飾を付記
  WriteLn(k);
end.Code language: PHP (php)

正常にコンパイルできます

列挙型と整数のキャスト

列挙型は不透明型に分類され、整数と直接代入することはできず、明示的なキャストが必要です:

  1. 列挙型 → 整数:Ord(列挙変数)
  2. 整数 → 列挙型:明示的型キャスト TAnimalKind(整数値)
  3. 整数を列挙型に変換する前に数値範囲を検証する必要があります:有効範囲 0 ~ Ord(High(列挙型))
type
  TAnimalKind = (akDuck, akCat, akDog);
var
  Kind: TAnimalKind;
  Num: Integer;
begin
  Kind := akCat;
  Num := Ord(Kind); // akCatの序数は1、Num=1

  Num := 2;
  // 範囲検証後にキャスト実行
  if (Num >= 0) and (Num <= Ord(High(TAnimalKind))) then
    Kind := TAnimalKind(Num);
end;Code language: JavaScript (javascript)
{$ifdef FPC} {$mode objfpc} {$H+} {$endif}
{$codepage utf8}

program EnumDemo;

type
  TAnimalKind = (akDuck, akCat, akDog);
var
  Kind: TAnimalKind;
  Num: Integer;
begin
  Kind := akCat;
  Num := Ord(Kind); // akCat index is 1,Num=1

  Num := 2;

  if (Num >= 0) and (Num <= Ord(High(TAnimalKind))) then
    Kind := TAnimalKind(Num);

  WriteLn(Num);//2
end.Code language: PHP (php)

列挙型

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です