Delphi泛型
来源:互联网 发布:win10清理软件 编辑:程序博客网 时间:2024/06/11 20:02
Delphi(pascal的扩展)一直有强大的类型系统。看看下面的实现简单的插入排序算法的示例代码(我使用Delphi 2009年):
01 unit InsSort;
02
03 interface
04
05 type
06 TItem = Integer;
07 TArray = array of TItem;
08
09 procedure InsertionSort(var A: TArray);
10
11 implementation
12
13 procedure InsertionSort(var A: TArray);
14 var
15 I, J: Integer;
16 Item: TItem;
17
18 begin
19 for I:= 1 + Low(A) to High(A) do begin
20 Item:= A[I];
21 J:= I - 1;
22 while (J >= Low(A)) and (A[J] > Item) do begin
23 A[J + 1]:= A[J];
24 Dec(J);
25 end;
26 A[J + 1]:= Item;
27 end;
28 end;
上面的代码对整数数组进行排序,如果我们需要处理字符串数组,我们所要做的就是把TItem声明从整数型转换为字
符串:
1 type
2 TItem = string;
如果我们的任务是进行整数和字符串数组排序,我们应该有两个单独的源代码单元(虽然他们只有一个词是不同的)。显然,这是重复的代码,不能用纯pascal解决。但是,Delphi有泛型,让我们用泛型来试试。
1 procedure InsertionSort<TItem>(var A: array of TItem);
先不要编译,如果我们需要使用泛型类,我们还需要一些手段比较泛型类型,所以我写了下面的简单泛型类:
01 type
02 TArray<TItem> = class
03 class function Compare(const L, R: TItem): Integer; static;
04 class procedure InsertionSort(var A: array of TItem); static;
05 end;
06
07 implementation
08
09 uses SysUtils, TypInfo;
10
11 class function TArray<TItem>.Compare(const L, R: TItem): Integer;
12 var
13 P: PTypeInfo;
14
15 begin
16 P:= TypeInfo(TItem);
17 case P^.Kind of
18 tkInteger: begin
19 if PInteger(@L)^ < PInteger(@R)^ then Result:= -1
20 else if PInteger(@L)^ > PInteger(@R)^ then Result:= 1
21 else Result:= 0;
22 end;
23 tkUString: Result:= CompareStr(PString(@L)^, PString(@R)^);
24 end;
25 end;
26
27 class procedure TArray<TItem>.InsertionSort(var A: array of TItem);
28 var
29 I, J: Integer;
30 Item: TItem;
31
32 begin
33 for I:= 1 + Low(A) to High(A) do begin
34 Item:= A[I];
35 J:= I - 1;
36 // while (J >= Low(A)) and (A[J] > Item) do begin
37 while (J >= Low(A)) and (Compare(A[J], Item) > 0) do begin
38 A[J + 1]:= A[J];
39 Dec(J);
40 end;
41 A[J + 1]:= Item;
42 end;
43 end;
它能工作,不过它看起来很丑陋,如果考虑到泛型比较疯狂的开销的话,特别是像通常由普通汇编指令比较整数类型只用一个单一指令。 Delphi2009的RTL(Generics.Defaults.pas 单元文件)在IComparer泛型接口的基础上提供了更优雅(也更长)的解决方案的,但它归结到底还是使用一个低效率的运行时类型信息。
但是,为什么我们需要'比较'的功能呢?当编译器为泛型TItem类型生成代码时,编译器应该已经知道TItem的实际代替类型,编译器可以利用实际类型来生成更优雅的代码行
1 while .. (A[J] > Item) ..
效率远远高于下面这个:
1 while .. (Compare(A[J], Item) > 0) ..
泛型直接比较的思想还涉及到Haskell的'类型的类'的概念。在'类型类'跟OOP类有很大的不同。 在Haskell中每个类型是许多类型类的实例。例如整数类型是'Eq'类型类的实例,因为整数可以比较相等,也是'ord'类型类的实例,因为所有的比较操作(<,<=,>,> =)适用于整数,也是'Show'类型类,因为整数可以转换为字符串,等等.在我们的情况下,泛型TItem类型应该是一个'ord'类型类的实例。
网友在我以前的贴子评论中指出,我的泛型排序简单例程的TArrayRTL代码包含额外的开销,(Generic.Collections & Generic.Defaults 单元文件),因为是循环内使用RTTI。是的,这是真的。让我们改进RTTI的检查,采取循环外代码,同时保持代码简单(不使用复杂的IComparer接口)。
简单的任务,应该有简单的解决方案。现在,我的解决办法似乎很简单,我也花了几个小时才找到它 -泛型对初学者来说仍然很怪异。最后一步,让系统工作的代码是 在泛型类TArray里面 声明一个泛型过程类型TCompare ,没有它的代码将不能编译:
01
unit
GenericSort;
02
03
interface
04
05
type
06
TArray<T> =
class
07
public
type
08
TCompare =
function
(
const
L, R: T):
Integer
;
09
private
10
class
procedure
InternalSort(
var
A:
array
of
T;
11
Compare: TCompare); static;
12
public
13
class
procedure
InsertionSort(
var
A:
array
of
T); static;
14
end
;
15
16
function
CompareInt(
const
L, R:
Integer
):
Integer
;
17
18
implementation
19
20
uses
SysUtils, TypInfo;
21
22
class
procedure
TArray
.
InternalSort(
var
A:
array
of
T; Compare: TCompare);
23
var
24
I, J:
Integer
;
25
Item: T;
26
P: PTypeInfo;
27
28
begin
29
for
I:=
1
+ Low(A)
to
High(A)
do
begin
30
Item:= A[I];
31
J:= I -
1
;
32
while
(J >= Low(A))
and
(Compare(A[J], Item) >
0
)
do
begin
33
A[J +
1
]:= A[J];
34
Dec(J);
35
end
;
36
A[J +
1
]:= Item;
37
end
;
38
end
;
39
40
function
CompareInt(
const
L, R:
Integer
):
Integer
;
41
begin
42
if
L < R
then
Result:= -
1
43
else
if
L > R
then
Result:=
1
44
else
Result:=
0
;
45
end
;
46
47
class
procedure
TArray
.
InsertionSort(
var
A:
array
of
T);
48
var
49
P: PTypeInfo;
50
51
begin
52
P:= TypeInfo(T);
53
case
P^.Kind
of
54
tkInteger: InternalSort(A, @CompareInt);
55
tkUString: InternalSort(A, @CompareStr);
56
end
;
57
end
;
58
59
end
.
请注意该'CompareInt'函数在接口部分声明。如果你注释掉接口声明编译会出错误
- Delphi 泛型
- Delphi 泛型
- Delphi泛型
- DElphi
- Delphi
- delphi...
- Delphi~~
- Delphi @ ^
- Delphi
- delphi
- Delphi
- delphi
- Delphi
- Delphi
- Delphi
- DELPHI
- Delphi
- Delphi
- 【攻略】如何将DNS从新网转到DNSPod?
- 关于8253 芯片计数器初值的问题
- XMLHTTPRequest的属性和方法简介
- C#学习之接口
- 远程桌面端口
- Delphi泛型
- 新建类在ClassView中不能显示问题解决办法
- linux中shell命令
- 使用Eclipse工具 签名【android开发】
- socket实现大型文件传输 .
- c#学习体会:使用 ref 和 out 传递数组(downmoon)
- JavaMail附件中文名称乱码
- svn常用方法,自己研究了3天的结果,希望给各位提供便利
- c#中通过值和引用传递参数(downmoon)