官方描述
Unit that implements generic container classes to group data items in arrays, dictionaries, lists, stacks, queues, and more.
译文:实现泛型容器类的单元,以在数组中对数据项进行分组,词典,列表,堆栈,队列等。
起初在接触到Delphi的时候我以为没有这一部分内容,所有的都要自己实现,此处请原谅我的无知。。。。
关于从那个版本开始支持泛型的,我在官方文档上没有找到对应的说明,也可能是我英语太菜,在官网迷路了。
根据百度得来的结果2007的版本没有(真百度的)支持2009的版本(万一老师的博客上引用的也是这个版本)开始出现,也就是最早支持泛型容器的版本应该是Delphi2009
聊泛型容器避不开的就是泛型的概念,之前看哔哩哔哩的网友留言从泛型一节就是开始懵逼了。其实大可不必,泛型可以理解为一个变量,它的值是一个具体的类型
嗯,其实也可以把它当作孙大圣,它可以变成任何东西
Collections单元
在这个单元内一共定义了13个容器类,我们在其中甚至可以看到线程队列。那么问题来了,我们需要精通或者学习所有的类吗?答案是否定的
容器类就我个人的理解其实一共有两大表现形式,一种是列表形式的像数组,而另一种形式则以 Key,Value 成对的形式。也就是说我们从中选择两个比较有代表性的类进行学习即可。下面是我选择的两个类
- System.Generics.Collections.TList:很明显这个是列表
- System.Generics.Collections.TDictionary:Dictionary这个单词翻译成中文是字典的意思,不知道为啥这么起名,它是K,V形式的代表
注意:在单元内我们还可以看到相似的类例如
System.Generics.Collections.TObjectList和
System.Generics.Collections.TList区别在于带有Object的类会在删除元素时释放对象,而没有带Object的不会释放
API代码
针对容器类学习的总原则是围绕增、删、改、查这几个核心的API功能即可,其他的就只能现用现查了,不知道别人写代码是什么习惯,我写代码的时候帮助文档基本上都是开着的。。。
下面是针对两个容器类的代码实现
TList
实体类(TStudent)代码
type
TStudent = class
private
FName: string;
public
property Name: string read FName write FName;
// 构造方法
constructor Create; overload;
// 有参构造方法
constructor Create(FName: string); overload;
end;
constructor TStudent.Create;
begin
end;
constructor TStudent.Create(FName: string);
begin
Self.FName := FName;
end;
操作类(即增、删、改、查),我没有使用内联,几次想用都删了
uses
System.Generics.Collections, System.SysUtils;
var
// 文档上的定义是TList,而我们的定义尖括号中的是TStudent,这就是泛型的用法
StudentList: TList;
// 循环中使用获取TList成员
Stu: TStudent;
begin
// 初始化学生列表
StudentList := TList.Create;
StudentList.add(TStudent.Create('小强'));
StudentList.add(TStudent.Create('萧蔷'));
StudentList.add(TStudent.Create('小黑'));
StudentList.add(TStudent.Create('小白'));
StudentList.add(TStudent.Create('小黄'));
// 开始之前输出一次
for Stu in StudentList do begin
Writeln('学生信息是:' + Stu.Name);
end;
// 泛型容器自带的删除函数,偷个懒
StudentList.Delete(0);
// 修改,查询到指定的学生,修改其值即可
StudentList.Items[0].Name := '小白';
// 查询,其实和数组的操作没有太大区别
for Stu in StudentList do begin
Writeln('学生信息是:' + Stu.Name);
end;
end.
TDictionary
此类容器的特点是 key 唯一,并且几乎所有的操作都是根据 key 来的
改造下实体类(TStudent)增加一个属性,代码如下
type
TStudent = class
private
FName: string;
FId: string;
public
property Name: string read FName write FName;
property Id: string read FId write FId;
// 构造方法
constructor Create; overload;
// 有参构造方法
constructor Create(FName: string; FId: string); overload;
end;
constructor TStudent.Create;
begin
end;
constructor TStudent.Create(FName: string; FId: string);
begin
Self.FName := FName;
end;
操作类(即增、删、改、查)
{注意单元的引用}
uses
System.Generics.Collections, System.SysUtils;
var
// 文档上的定义是TList,而我们的定义尖括号中的是TStudent,这就是泛型的用法
StudentMap: TDictionary;
// 循环中使用获取TList成员
Key: string;
Student,Stu: TStudent;
begin
// 初始化学生列表
StudentMap := TDictionary.Create;
// 此处的添加其实并不是太好,根据文档描述,当我们添加的元素的key已经存在会抛出异常
// 建议使用AddOrSetValue
StudentMap.add('1001', TStudent.Create('1002', '小强'));
StudentMap.add('1002', TStudent.Create('1001', '萧蔷'));
StudentMap.add('1003', TStudent.Create('1003', '小黑'));
StudentMap.add('1004', TStudent.Create('1004', '小白'));
StudentMap.add('1005', TStudent.Create('1004', '小黄'));
// 注意此处获取是key,也就是1001 1002这些东西
for Key in StudentMap.Keys do begin
// 获取到key之后,再根据key获取对应value也就是学生对象
// 这里的获取方式有点儿任性居然要的是一个指针,而不是直接返回
StudentMap.TryGetValue(Key, Student);
// 最好判断一下,否则容易出现空指针
if (Student <> nil) then
Writeln('学生信息是:' + Student.Name)
end;
// 删除元素,无论什么操作都是通过key去操作,因为key是不可以重复的
StudentMap.Remove('1005');
// 修改,没有就添加,有就更新
StudentMap.AddOrSetValue('1004', TStudent.Create('1004', '小黄'));
// 直接获取value
for Stu in StudentMap.values do begin
// 最好判断一下,否则容易出现空指针
if (Stu <> nil) then
Writeln('学生信息是:' + Student.Name)
end;
end.
参考资料
万一的博客:
https://www.cnblogs.com/del/category/113556.html官方文档:
http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Generics.Collections
本文暂时没有评论,来添加一个吧(●'◡'●)