源码技术
php
java
python
Linux
行业商讯
当前位置:
首页
>
java
>Delphi 编程 -- 三谈集合类型
Delphi 编程 -- 三谈集合类型
2026-08-27 12:27:56
Delphi 编程 -- 三谈集合类型
前面我们讨论了集合的操作,今天我们谈谈如何枚举集合的元素。
一般而言,集合主要用途在于判断个体是否属于集体,譬如对于词法分析程序,对于读取的字符,就需要判断它是哪个字符类:数集?操作符集合?其他符号集合?从而将其正确归类。
但有时候我们也会有相反的需求:枚举一个集合都包含哪些元素。
关于元素对集合的归属,Pascal 提供了 in 操作符,可以通过 e in someset 来方便地判断元素是否属于某个集合。但对于枚举一个集合,Pascal 则没有提供相关的操作手段。
所幸的是,Delphi 提供了两个关键的例程(routine),有助于实现我们的任务。
首先,Delphi 提供了获取类型运行时信息的 TypeInfo 函数:
TypeInfo 函数接受一个类型参数,返回指向该类型运行时结构 TTypeInfo 记录的指针。
其次,Delphi 还提供了 GetEnumName 函数:
GetEnumName 函数接受一个指向枚举类型的 TTypeInfo 记录的指针,以及一个枚举类型的整数值,返回该整数值对应的名字值。
有了这些准备,我们就可以枚举集合的元素了。
在这段代码中,我们已知 FSA 是一个集合,需要列出 FSA 集合的元素。
这里的 Low 和 High 函数返回 TFontStyle 枚举类型的第一个值和最后一个值,返回值仍然是 TFontStyle 类型,也是 FSA 集合的基类型,所以可以直接用于隶属关系的判断中。因为 GetEnumName 需要一个整数的枚举值,所以要用 Ord(fs) 来获得 fs 的序数值。
变量 prev 用于判断当前输出的元素之前是否已经有元素输出,如果有,则输出元素之间的分隔符。
最后的输出结果为:
这个列举集合元素的例子只对基类型是枚举类型的集合有意义,如果基类型是子界类型,则 GetEnumName 无意义(抛出异常)。
有了这段列举集合元素的代码,那能不能将这段代码一般化,使其不只限于 TFontStyle 类型呢?很自然地,我们就想到了泛型:
首先,Delphi 中也没有规范 T 为枚举类型或字节类型的语法手段,或许正因为如此,所以
Delphi 中不能定义 set of T 的泛型。因此上面的代码在 Delphi 中行不通。
顺便谈一下集合类型在 Pascal 中的实现。
当初 Wirth 先生为 Pascal 设计集合类型时,或许主要是为了写编译程序的方便。在他那本著名的《算法 + 数据结构 = 程序》著作中,在介绍了集合类型之后举的一个例子就是扫描程序。如果集合的主要目的是字符的归类,自然就是越简单越好。所以集合的内部实现就是一个机器字中所包含的位串。Delphi 规定集合基类型的值空间不能超过 256 个值,也就是一个字节的容量。
上面代码中的集合 FSA 的内部表示如下:
FSA 中含有 fsBold,又因为 fsBold 在基类型 TFontStyle 中的序数为 0,所以 FSA 的内部表示中的第 0 位为 1,同样道理,fsItalic 的序数是 1,所以 FSA 的第 1 位也置 1。而 fs in FSA 的内部实现是使用 bt 指令对相应的位进行测试,为 1 则表示元素属于集合,为 0 则表示不属于集合。
有了这个集合内部实现的基础,下面我们来实现通用的集合元素枚举过程。先来看测试程序:
为了对照,测试程序保留了上面的枚举代码。下面的三行是采用通用枚举过程对 FSA 集合元素的枚举。测试结果如下:
可以看出,两种枚举方法的结果一样。
下面是通用枚举过程的 Unit:
枚举过程的声明如下:
procedure EnumerateSet(var A; typeinfo: PTypeInfo);
EnumerateSet 过程接受两个参数:一个无类型参数 A,一个集合的 TypeInfo 指针。实现思路是:从集合的 TypeInfo 结构得到集合的基类型,枚举过程将基类型限制为枚举类型。从基类型得到 TypeData 结构,再从其中得到枚举类型的 Low 和 High,然后对 NameList 循环,循环过程中测试当前的枚举值是否在集合中,若在集合中,则输出当前枚举值得名字值,然后继续下一轮循环,循环到 High 结束。
尽管有各种限制,但集合类型和枚举类型结合起来,在某些场合还是很有用的,尤其是集合实现的高效率,是其他的判断/比较语句所不及的。
相关阅读
Delphi 编程 -- 集合类型
Delphi 编程 -- 再谈集合类型
本文来自网友投稿或网络内容,如有侵犯您的权益请联系我们删除,联系邮箱:596563534@qq.com 。
“主网小闪”不是一串代码,是我们写给时间的誓言!
安联锐视(股票代码:301042.SZ)是一家专注于安防视频监控产品软硬件研发、生产与销售的高新技术企业
最新文章
“主网小闪”不是一串代码,是我们写给时间的誓言!
云程万里⨉中阳一中 | 课堂进行时:编程小游戏 + AI初体验
阿里平头哥拟独立上市(附核心概念股+代码一键导入)
写代码(二):从一个Swiper拖拽Bug看前端调试与系统思维
2024【研究】具有可编程功能的数字机械超材料
别再卡壳了!这些个单词让你代码速度翻3倍
2026年副高康复医学技术题库【代码056】康复医学习题(3)
威力洗衣机故障代码
科技素养培育路径规划,编程、机器人、科创该怎么选?
Skill_Seekers,一键把代码库变成Skill
热门文章
用AI工具写代码的一点心得
发布了一个编程相关的服务
Three.js 入门:30行代码画出你的第一条3D线条
选择编程等级考试的关键:权威性、科学性与实用价值如何权衡
华科不日常57话: 熬夜跑代码,7小时后看老板怼不怼我
幼儿编程考试时间怎么安排?适合6-12岁孩子的考期参考
pencil.dev在代码中进行设计
苏州家长必看!少儿编程兴趣班精选指南,选对不踩坑
代码选错,标书白写!国自然医学部7大“送命”雷区详解(附:医学科学部申请详表)
2026全年编程赛事预览+白名单赛事解读
随机文章
10个月宝宝每天需要喝多少奶粉?
编程两三事:辞达而已矣
跟着大佬学习python,把python做成了APP
练完这70个项目,你的Python就牛了
乱写CATOptTK过程中的笔记 - Python/PySide6属性
栋察宇宙(四十七):Python 正则表达式
从 Python 小白到实战高手,这本「正统指南」让你摆脱野路子!【内附PDF版电子书】!!
揭秘!如何用Python爬虫抓取你想要的数据!
这108个Python项目练完你就牛了
如何安装python的ovito接口
Python爬取百度新闻