随笔 - 2047  文章 - 71 评论 - 10629 trackbacks - 253

提示1: 点击 标题 可进入首页;   提示2: 从搜索引擎中搜索 万一 可迅速找到这里.
昵称:万一
园龄:4年3个月
荣誉:推荐博客
粉丝:349
关注:34

随笔分类(2499)

随笔档案(2051)

积分与排名

  • 积分 - 4148339
  • 排名 - 4

最新评论


一、使用泛型类:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

  TArr<T> = class
    class procedure ArrayAdd(var Arr: TArray<T>; const item: T);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TArr<T> }

class procedure TArr<T>.ArrayAdd(var Arr: TArray<T>; const item: T);
begin
  SetLength(Arr, Length(Arr)+1);
  Arr[High(Arr)] := item;
end;

//测试
procedure TForm1.FormCreate(Sender: TObject);
var
  arr1: TArray<string>;
  arr2: TArray<Integer>;
begin
  TArr<string>.ArrayAdd(arr1, 'abc');
  TArr<Integer>.ArrayAdd(arr2, 123);
  ShowMessageFmt('%s,%d', [arr1[0], arr2[0]]); //abc,123
end;

end.


二、使用泛型结构:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

  TArr<T> = record //record
    class procedure ArrayAdd(var Arr: TArray<T>; const item: T); static; //结构中的 class 方法必须是 static 的
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TArr<T> }

class procedure TArr<T>.ArrayAdd(var Arr: TArray<T>; const item: T);
begin
  SetLength(Arr, Length(Arr)+1);
  Arr[High(Arr)] := item;
end;

//测试
procedure TForm1.FormCreate(Sender: TObject);
var
  arr1: TArray<string>;
  arr2: TArray<Integer>;
begin
  TArr<string>.ArrayAdd(arr1, 'abc');
  TArr<Integer>.ArrayAdd(arr2, 123);
  ShowMessageFmt('%s,%d', [arr1[0], arr2[0]]); //abc,123
end;

end.


三、在类或结构中建立泛型方法:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

  TArr = record
    class procedure ArrayAdd<T>(var Arr: TArray<T>; const item: T); static;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TArr }

class procedure TArr.ArrayAdd<T>(var Arr: TArray<T>; const item: T);
begin
  SetLength(Arr, Length(Arr)+1);
  Arr[High(Arr)] := item;
end;

//测试
procedure TForm1.FormCreate(Sender: TObject);
var
  arr1: TArray<string>;
  arr2: TArray<Integer>;
begin
  TArr.ArrayAdd<string>(arr1, 'abc');
  TArr.ArrayAdd<Integer>(arr2, 123);
  ShowMessageFmt('%s,%d', [arr1[0], arr2[0]]); //abc,123
end;

end.


四、扩充 System.Generics.Collections 单元中的 TArray 类:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Generics.Collections;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

  Txxx = class helper for TArray
    class procedure ArrayAdd<T>(var Arr: TArray<T>; const item: T); static;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ Txxx }

class procedure Txxx.ArrayAdd<T>(var Arr: TArray<T>; const item: T);
begin
  SetLength(Arr, Length(Arr)+1);
  Arr[High(Arr)] := item;
end;

//测试
procedure TForm1.FormCreate(Sender: TObject);
var
  arr1: TArray<string>;
  arr2: TArray<Integer>;
begin
  TArray.ArrayAdd<string>(arr1, 'abc');
  TArray.ArrayAdd<Integer>(arr2, 123);
  ShowMessageFmt('%s,%d', [arr1[0], arr2[0]]); //abc,123
end;

end.


总结:

1、Delphi 的泛型方法只能属于一个类或结构, 这是好事, 也应该是 Delphi 所提倡的; 这便于管理、也便于快速输入.

2、稍稍扩充一下就可让动态数组和其它强大的列表类比拼一下了.

3、这也像是 C++ 中的算法了, 按这个思路应该可以把许多 C++ 中的算法移植过来.

posted on 2011-12-24 11:57 万一 阅读(778) 评论(18) 编辑 收藏

FeedBack:
#1楼 2011-12-24 21:36 一人游走      
期待移值!
 回复 引用 查看   
#2楼 2011-12-25 08:29 老神仙      
谢谢万一的圣诞礼物,也祝你圣诞快乐!
现在关于泛型,有一件事请教,怎样能把泛型类作为参数,实现函数的多态?例如func(T),调用时,可以是func(string),可以使func(integer)???

 回复 引用 查看   
#3楼[楼主2011-12-25 08:42 万一      
@老神仙
这应该是 overload 了.

 回复 引用 查看   
#4楼 2011-12-25 20:54 老神仙      
@万一
谢谢,重载可以,就是没有找到一个通用的方式

 回复 引用 查看   
#5楼[楼主2011-12-25 21:05 万一      
@老神仙
一般情况下, 这个不会有通用方式.
因为对不同的数据类型, 函数实现方式会有很大的不同.
泛型避免的是代码重复.

 回复 引用 查看   
#6楼 2011-12-25 21:26 老神仙      
@万一
其实也是一种贪心,以前没有泛型,也没有这种想法,其实利用泛型,有时候效率不是很高,就是代码简洁,因为泛型在编译的时候是不能确定类型的,所以在运行时,就会出现效率问题。

 回复 引用 查看   
#7楼 2011-12-25 21:34 老神仙      
我很担心delphi走了.net的道路,.net已经走向了一个非常不好的道路,效率越来越慢,各种事体框架,飞原生的代码,各种动态类型等等,最可怕的是,未来微软不让你知道技术细节,开发走向垄断。
 回复 引用 查看   
#8楼 2011-12-30 15:28 清闲轩      
刚刚注册,看到万一老师的博客很详细,就来学习一下了。
我是一个C++程序员,出于爱好,想接触一下Delphi。用Delphi XE2,使用泛型的时候,效果很不理想。Delphi的泛型基本上只是强制类型转换的一种编译时替代,与C++的模板相比…或者没有可比性吧。
例如我已经有一种类型T,必定有方法f,则代码:
Test = record:
class procedure ABC<T>(t: T);static;
end;

procedure Test.ABC<T>(t: T);
begin
t.f;//直接就错误了…
end;

另外,delphi的泛型不支持类成员方法,很是困扰。
请问万一老师,对于我列出的示例代码,有方法实现吗(静多态)?
其实如果这个不支持,C++的算法大多数是不能被搬迁过来的。

 回复 引用 查看   
#9楼 2011-12-30 20:33 TasNat      
恶心死了
TArr.ArrayAdd<string>(arr1, 'abc');
如果做不到
arr1.ArrayAdd('abc');
就不要出来献丑了嘛

 回复 引用 查看   
#10楼 2011-12-30 20:40 水桶      
万老师:线程的几种插入方式及其实现的源码,可否示范?谢谢!祝老师元旦快乐!
 回复 引用 查看   
#11楼[楼主2011-12-31 13:38 万一      
@TasNat
每个学习编程的人, 可能都有被误导过.

 回复 引用 查看   
#12楼[楼主2011-12-31 13:39 万一      
@水桶
新年快乐

 回复 引用 查看   
#13楼 2011-12-31 13:55 清闲轩      
@万一
求万一老师看一下8楼!谢谢!!

 回复 引用 查看   
#14楼[楼主2011-12-31 14:18 万一      
@清闲轩
先看看: System.Generics.Collections 单元的源码
你说: "Delphi的泛型基本上只是强制类型转换的一种编译时替代", 听谁说的?

 回复 引用 查看   
#15楼 2011-12-31 14:40 清闲轩      
@万一
不是听谁说的
DELPHI有关泛型的文档我看过了。
对于以下的错误就足矣说明了。也就是T不能是假定任何类型(除非已经是限定声明了是某个类型的派生类)
procedure Test.ABC<T>(t: T);
begin
t.f;//直接就错误了…
end;
为什么会有这种情况?
假定我实现了好几个类(无派生继承关系),但是他们都用共同方法f,那么这样使用是符合需求的。DELPHI文档中所用的泛型,无法支持对类型的假定(把模板代码生成推迟到模板被使用时再去匹配生成代码),那么这种泛型,只不过是类型替代。也就是最多能用他们实现容器,而不能有效实现逻辑算法(撇开传入地址指针来满足算法逻辑的比较判断)。

 回复 引用 查看   
#16楼 2011-12-31 14:48 清闲轩      
@万一
System.Generics.Collections 单元的源码
这个就是我说的容器源码了。我就想问问有没有方法可以实现到我要的那种使用方式(或者使用其他技巧)看一下下面的代码:
Compare = record
class function comp<T>(p1: T; p2: T): Boolean; static;
end;

class function Compare.comp<T>(p1: T; p2: T): Boolean;
begin
if p2 > p1 then
Result := True
else
Result := False
end;

我使用这个模板函数的时候,就是传入一个已经重载了>的对象,或者是整形之类支持>运算符的变量,DELPHI提示错误,不允许这样实现。
那万一老师你说说,这样的泛型除了只能实现容器外,还能实现算法吗?
如果要传入一个比较函数的地址,如:
type COMPARER<T> = function(p1:T;p2:T):Boolean;
class function Compare.comp<T>(p1: T; p2: T; comparer2:COMPARER<T>): Boolean;

这样的实现,不觉得这样的泛型只是单纯的类型替代了吗?

 回复 引用 查看   
#17楼[楼主2011-12-31 15:22 万一      
@清闲轩
估计你是个领导, 或曾经做过领导. 因为你太习惯下结论了, 譬如:
看过 Collections.pas 后就说: "也就是最多能用他们实现容器"...

另外你举得例子我看不懂, Delphi 不允许这种代码: t: T, 因为它大小写不敏感.

C++ 泛型多年后才有了 Delphi 的泛型, 我想除了区别外、还应该有进步.

慢慢习惯吧, 等彻底了解后, 希望你能再盘点下它的不足.

 回复 引用 查看   
#18楼 2011-12-31 15:26 清闲轩      
@万一
被讽刺了呢,呵呵。没事,我只是一个普通的爱好者。
嗯,一下子手快写出了C++式的代码了,抱歉。
请万一老师再看看16楼。

 回复 引用 查看   
#19楼 2012-02-04 11:19 好小爱新      
还真不知道Delphi处理泛型是怎样做的。
不过对于C++来说,泛型都是在编译期展开的,所以没有运行期的类型识别开销:)
个人感觉如果Delphi真的是占用运行期的时间,那损失真的有点儿大了:)
不过DCC和BCC一直不支持连接期全程序优化,所以如果Delphi程序已编译成静态库还支持泛型的话,那应该就暂无它法了:)

 回复 引用 查看