Pascal 枚举

一、枚举类型(Enumerated Type)

Pascal 的枚举是封装性很好的不透明类型,日常开发使用频率远高于其他语言的枚举。

基础定义写法

type
  TAnimalKind = (akDuck, akCat, akDog);

约定:枚举常量名增加类型缩写双字母前缀

  • 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; // not 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; // not TAnimalKind.
  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)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注