CnPack Forum » 技术板块灌水区 » [D2009]泛型+闭包能带来什么?


2008-9-27 09:45 shenloqi
[D2009]泛型+闭包能带来什么?

[font=Arial][size=2]    D2009中引入了Unicode,泛型和闭包。(D2009.Net还没有发布,据说会把所有.Net的东西都加上,包括LINQ,WPF,SilverLight,甚至包括Linux平台的Mono运行)泛型和闭包虽然.Net中早就有了,但是还有不少人理解不是很深。我前段时间也经常看到有些老外在博客上就D2009给出的闭包等提出讨论,说闭包没有什么用,闭包可以做的我们用本地函数或者函数指针应该也能做到等等。[/size][/font]
[font=Arial][size=2]    泛型一般情况下的用途是用于强类型的集合和容器,闭包一般可以用于简化API(尤其是回调)定义和使用。[/size][/font]
[font=Arial][size=2]    但是作为程序员,就要能够最大程度的利用工具的能力,泛型和闭包这些功能除了一些常规用途之外,我们还能用它们做什么呢?[/size][/font]
[font=Arial][size=2]    我已经曾经利用接口的引用计数做过ScopeGuard并给大家演示过,也有过其他的很多其他的用途,但是用起来都有些繁琐。在有了泛型之后,CodeGear编译器组的Barry写了一个博客介绍了他的TSmartPointer<T>,可以实现自动释放创建的对象,用法如下:[/size][/font]
[font=Arial][size=2][font=Courier New]var
  tmpObj: TSmartPointer<TObject>;
begin
  tmpObj := TObject.Create('Test');
  Memo1.Lines.Add(tmpObj.Value.ToString);
end;[/font]
可以看到该类的使用还是比较简单的,并可以通过Value这个字段来访问原对象,tmpObj对象无需显示释放,当超过其生命周期时自己会释放。[/size][/font]
[font=Arial][size=2]    此后CodeGear的首席架构师Allen也写出一篇博文,介绍了如何组合泛型+闭包实现.Net的Lock和Using关键字的功能,可算是相当精彩(可惜没有解决闭包中无法退出函数主体的问题,不过这应该不算问题),用法如下:[/size][/font]
[font=Arial][size=2]Lock的例子:(Allen的例子没有这么简洁,我用class helper辅助了一下,个人感觉这样一来真的是不需要.NET的Lock关键字了)[/size][/font]
[font=Arial][size=2][font=Courier New]  Self.Lock(Self, procedure
    begin
      Memo1.Lines.Add('Hello world!');
    end);[/font]
Using的例子:(我同样稍微修改了一下)[/size][/font]
[font=Courier New][size=2]  TStringList.Create.Using<TStringList>(procedure (List: TStringList)
    begin
      List.Add('Test 1');
      Memo1.Lines.AddStrings(List);
    end);
[font=Arial]    可以看到Lock用法是相当简洁有效的,而Using虽然要带入类型,但是也不繁琐,而且还无需给临时生成的这个TStringList赋一个变量。[/font][/size][/font]
[font=Arial][size=2]    我昨晚想了一下,首先我们应该可以给闭包增加额外的Break,Continue和Exit的支持,其次,我们还能够通过泛型和闭包做很多别的以前比较难做到的事情,大家知道闭包是函数式语言的基础,有了闭包之后,函数式语言无需流程操作和变量赋值就可以做到图灵完备,所以只要有泛型+闭包,我们就应该可以做到无需流程。[/size][/font]
[font=Arial][size=2]    当然,由于在Delphi,C系列甚至是最新的C#中,函数都不是First Class的,所以要想做到跟函数式语言那样简便是有难度的,而且目前Delphi还不支持Lambda表达式,所以写起来就更繁琐了,但是这也是一个有意思的尝试。我是拿Case语句作为第一个实验品的,我们知道Delphi,Java,C系列等语言都有类似Case的语句,但是这些语句都只能针对整形操作,不支持字符串和对象等,所以我的这个尝试就是实现支持所有的类型的Case语句模拟,当前的版本使用的效果如下:[/size][/font]
[font=Courier New][size=2]  Flow._Case(Memo1.Lines[0])._Of('Test 1', procedure (s: string)
    begin
      Memo1.Lines.Add('Proc1: ' + s);
    end)._Of('Test 2', procedure (s: string)
    begin
      Memo1.Lines.Add('Proc2: ' + s);
    end)._Else(procedure (s: string)
    begin
      Memo1.Lines.Add('Not Matched: ' + s);
    end);[/size][/font]
[font=Arial][size=2]    代码中繁琐的地方就是Delphi的闭包没有Lambda那么简单。该段代码支持Delphi的代码提示,_Case之后可以有任意多的_Of条件,而_Else则只能出现一次,并只能在最后出现。除了Case之外,还有各种循环和异常处理等都可以通过这种方式处理。我验证了概念之后除非实际需要一般不会写全,所以估计不太可能把所有想到的都试验一下了,但是希望这篇文章能让大家对如何发挥工具的能力再多一些理解(希望大家能够改写成.Net版本或者在.Net中实现更好的主意)。[/size][/font]
[font=Courier New][size=2][/size][/font]
[font=Courier New][size=2]附上文中提及的代码:[/size][/font]
[font=Courier New][size=2][/size][/font]
[font=Courier New][size=2]unit DelphiUtils;[/size][/font]

[font=Courier New][size=2]interface[/size][/font]

[font=Courier New][size=2]uses
  SysUtils, Classes;[/size][/font]

[font=Courier New][size=2]type
  ObjHelper = class helper for TObject
    procedure Lock(Proc: TProc); overload;
    class procedure Lock(O: TObject; Proc: TProc); overload; static;
    procedure Using<T: class>(Proc: TProc<T>); overload;
    class procedure Using<T: class>(O: T; Proc: TProc<T>); overload; static;
  end;[/size][/font]

[font=Courier New][size=2]  TLifetimeWatcher = class(TInterfacedObject)
  private
    FWhenDone: TProc;
  public
    constructor Create(const AWhenDone: TProc);
    destructor Destroy; override;
  end;[/size][/font]

[font=Courier New][size=2]  TSmartPointer<T: class> = record
  strict private
    FValue: T;
    FLifetime: IInterface;
  public
    constructor Create(const AValue: T); overload;
    class operator Implicit(const AValue: T): TSmartPointer<T>;
    property Value: T read FValue;
  end;[/size][/font]

[font=Courier New][size=2]  TBlockResult = (brNormal, brBreak, brContinue, brExit);[/size][/font]

[font=Courier New][size=2]  IBlockResult = interface
    ['{17DF93D7-88D5-4B37-B6A4-15C29141BAA4}']
    function GetBlockResult: TBlockResult;
    procedure SetBlockResult(Value: TBlockResult);
    property BlockResult: TBlockResult read GetBlockResult write SetBlockResult;
  end;[/size][/font]

[font=Courier New][size=2]  TBlockResultImpl = class(TInterfacedObject, IBlockResult)
  private
    FBlockResult: TBlockResult;
  public
    function GetBlockResult: TBlockResult;
    procedure SetBlockResult(Value: TBlockResult);
    property BlockResult: TBlockResult read GetBlockResult write SetBlockResult;
  end;[/size][/font]

[font=Courier New][size=2]  ICaseOf<T> = interface
    ['{66546C18-162C-4B11-B385-07C35C9D5CAB}']
    function _Of(AValue: T; Proc: TProc<T>): ICaseOf<T>;
    procedure _Else(Proc: TProc<T>);
  end;[/size][/font]

[font=Courier New][size=2]  TCaseOf<T> = class(TInterfacedObject, ICaseOf<T>)
  private
    FValue: T;
    FMatched: Boolean;
  public
    function _Of(AValue: T; Proc: TProc<T>): ICaseOf<T>;
    procedure _Else(Proc: TProc<T>);
    constructor Create(AValue: T);
  end;[/size][/font]

[font=Courier New][size=2]  Flow = record
  public
    class function _Case<T>(AValue: T): ICaseOf<T>; static;
    class function _CaseEx<T>(Func: TFunc<T>): ICaseOf<T>; static;
  end;[/size][/font]

[font=Courier New][size=2]implementation[/size][/font]

[font=Courier New][size=2]uses
  Generics.Defaults;[/size][/font]

[font=Courier New][size=2]procedure ObjHelper.Lock(Proc: TProc);
begin
  Lock(Self, Proc);
end;[/size][/font]

[font=Courier New][size=2]class procedure ObjHelper.Lock(O: TObject; Proc: TProc);
begin
  TMonitor.Enter(O);
  try
    Proc();
  finally
    TMonitor.Exit(O);
  end;
end;[/size][/font]

[font=Courier New][size=2]procedure ObjHelper.Using<T>(Proc: TProc<T>);
begin
  Using<T>(Self, Proc);
end;[/size][/font]

[font=Courier New][size=2]class procedure ObjHelper.Using<T>(O: T; Proc: TProc<T>);
begin
  try
    Proc(O);
  finally
    O.Free;
  end;
end;[/size][/font]

[font=Courier New][size=2]{ TLifetimeWatcher }[/size][/font]

[font=Courier New][size=2]constructor TLifetimeWatcher.Create(const AWhenDone: TProc);
begin
  FWhenDone := AWhenDone;
end;[/size][/font]

[font=Courier New][size=2]destructor TLifetimeWatcher.Destroy;
begin
  if Assigned(FWhenDone) then
    FWhenDone;
  inherited;
end;[/size][/font]

[font=Courier New][size=2]{ TSmartPointer<T> }[/size][/font]

[font=Courier New][size=2]constructor TSmartPointer<T>.Create(const AValue: T);
begin
  FValue := AValue;
  FLifetime := TLifetimeWatcher.Create(procedure
  begin
    AValue.Free;
  end);
end;[/size][/font]

[font=Courier New][size=2]class operator TSmartPointer<T>.Implicit(const AValue: T): TSmartPointer<T>;
begin
  Result := TSmartPointer<T>.Create(AValue);
end;[/size][/font]

[font=Courier New][size=2]{ TBlockResultImpl }[/size][/font]

[font=Courier New][size=2]function TBlockResultImpl.GetBlockResult: TBlockResult;
begin
  Result := FBlockResult;
end;[/size][/font]

[font=Courier New][size=2]procedure TBlockResultImpl.SetBlockResult(Value: TBlockResult);
begin
  FBlockResult := Value;
end;[/size][/font]

[font=Courier New][size=2]{ Flow }[/size][/font]

[font=Courier New][size=2]class function Flow._Case<T>(AValue: T): ICaseOf<T>;
begin
  Result := TCaseOf<T>.Create(AValue);
end;[/size][/font]

[font=Courier New][size=2]class function Flow._CaseEx<T>(Func: TFunc<T>): ICaseOf<T>;
var
  AValue: T;
begin
  if Assigned(Func) then
    AValue := Func()
  else
    AValue := Default(T);
  Result := TCaseOf<T>.Create(AValue);
end;[/size][/font]

[font=Courier New][size=2]{ TCaseOf<T> }[/size][/font]

[font=Courier New][size=2]constructor TCaseOf<T>.Create(AValue: T);
begin
  FValue := AValue;
  FMatched := False;
end;[/size][/font]

[font=Courier New][size=2]procedure TCaseOf<T>._Else(Proc: TProc<T>);
begin
  if (not FMatched) and Assigned(Proc) then
  begin
    FMatched := True;
    Proc(FValue);
  end;
end;[/size][/font]

[font=Courier New][size=2]function TCaseOf<T>._Of(AValue: T; Proc: TProc<T>): ICaseOf<T>;
begin
  Result := Self;
  if (not FMatched) and Assigned(Proc) and
    (TComparer<T>.Default.Compare(AValue, FValue) = 0) then
  begin
    FMatched := True;
    Proc(FValue);
  end;
end;[/size][/font]

[font=Courier New][size=2]end.[/size][/font]

2008-9-27 11:25 Passion
闭包与本地函数指针的关键区别在于前者有对当时环境上下文的记录而后者没有。

2009-7-24 11:50 jokeli
thanks for!great job!:victory::lol:
[url=http://sale09.blog3.petitmall.jp/blog-entry-2.html].[/url][url=http://sale09.eklablog.com/article-116442-575923.html].[/url][url=http://sale09.jugem.jp/?eid=2].[/url][url=http://showsale.journalhub.com/2009/07/13/feeling/].[/url][url=http://www.showsale.blogonize.com/print/18941.html].[/url][url=http://blog.24reader.com/showsale/2009/07/13/idea/].[/url][url=http://sale09.saitamania.net/e101846.html].[/url][url=http://sale09.hamazo.tv/e1900615.html].[/url][url=http://blog.sandiegotown.com/showsale/?eid=24129].[/url][url=http://sale0909.unblog.fr/2009/07/11/3/].[/url][url=http://sale09.blogspot.es/1247471298/%E8%87%AA%E5%B7%B1%E6%B1%BA%E5%AE%9A%E8%87%AA%E5%B7%B1%E6%88%90%E5%B0%B1%E7%9A%84%E9%AB%98%E4%BD%8E/].[/url][url=http://showsale.blogmas.com/2009/07/12/love/].[/url][url=http://showsale.blogetery.com/2009/07/13/true/].[/url][url=http://showsale.blogage.de/entries/2009/7/13/---].[/url][url=http://showsale.uniterre.com/94211/%E5%8D%81%E5%B9%B4%E5%BE%8C%EF%BC%8C%E8%A8%98%E5%BE%97%E4%BE%86%E5%A8%B6%E6%88%91.html].[/url][url=http://showsale.tumblr.com/post/139455860].[/url][url=http://sale09.createblog.com/blog/entry.php?id=25620].[/url][url=http://sale09.namjai.cc/e11188.html].[/url][url=http://sale09.ti-da.net/e2493716.html].[/url][url=http://sale09.i-yoblog.com/e184031.html].[/url][url=http://sale09.da-te.jp/e194603.html].[/url][url=http://sale09.blog.lu/post/706/3719].[/url][url=http://blog.bitcomet.com/goodshow/post_102459/].[/url][url=http://showsale.blog.com/2009/07/11/soul/].[/url][url=http://hk.myblog.yahoo.com/linsale18/article?mid=3].[/url][url=http://sale0909.spaces.live.com/blog/cns%21B9BB131DA7A2ECC6%21117.entry].[/url][url=http://sale09.mysinablog.com/index.php?op=ViewArticle&articleId=1818263].[/url][url=http://showsale.blog126.fc2.com/blog-entry-1.html].[/url][url=http://blog.qooza.hk/sale09?eid=14150278].[/url][url=http://showsale.ycool.com/post.3413077.html].[/url][url=http://blog.sina.com.tw/showsale/article.php?pbgid=84400&entryid=595627].[/url][url=http://diary.blog.yam.com/showsale/article/7435347].[/url][url=http://showsale.blogspot.com/2009/07/blog-post_10.html].[/url][url=http://sale09.pixnet.net/blog/post/26299116].[/url][url=http://tw.myblog.yahoo.com/linsale18/article?mid=2].[/url][url=http://www.wretch.cc/blog/linsale18/454183].[/url][url=http://www.33db.com/index.php?op=ViewArticle&articleId=19&blogId=8].[/url][url=http://blog.xuite.net/sale09/blog/25322514].[/url][url=http://sale09.blog.ithome.com.tw/post/2222/28484].[/url][url=http://fashionshow99.blogspot.com/2009/07/blog-post_10.html].[/url][url=http://hi.fdlive.com/node/12092].[/url][url=http://fashionshow99.xanga.com/706855269/2345026399223203573133258240492816538646/].[/url][url=http://blog.sina.com.tw/fashionshow/article.php?pbgid=84417&entryid=586154].[/url][url=http://meco.namjai.cc/e11150.html].[/url][url=http://blog.qooza.hk/fashionshow?eid=14148496].[/url][url=http://blog.yam.com/fashionshow99/article/22592404].[/url][url=http://hk.myblog.yahoo.com/memegoli/article?mid=2].[/url][url=http://blog.bitcomet.com/fashionshow/post_102365/].[/url][url=http://tw.myblog.yahoo.com/memegoli/article?mid=2].[/url][url=http://fashionshow99.spaces.live.com/blog/cns%211C8FBE4D48B94A43%21123.entry].[/url][url=http://sale09.blog3.petitmall.jp/blog-entry-1.html].[/url][url=http://sale09.eklablog.com/article-116442-575921.html].[/url][url=http://sale09.jugem.jp/?eid=1].[/url][url=http://showsale.journalhub.com/2009/07/13/men/].[/url][url=http://www.showsale.blogonize.com/print/18940.html].[/url][url=http://blog.24reader.com/showsale/2009/07/13/old/].[/url][url=http://sale09.saitamania.net/e101845.html].[/url][url=http://sale09.hamazo.tv/e1900609.html].[/url][url=http://blog.sandiegotown.com/showsale/?eid=24127].[/url][url=http://sale0909.unblog.fr/2009/07/13/4/].[/url][url=http://sale09.blogspot.es/1247471439/%E5%BE%9E%E7%A0%B4%E6%B0%B4%E6%A1%B6%E4%B8%AD%E7%9C%8B%E5%88%B0%E7%9A%84%E5%93%B2%E7%90%86/].[/url][url=http://showsale.blogmas.com/2009/07/12/word/].[/url][url=http://showsale.blogetery.com/2009/07/13/summer/].[/url][url=http://showsale.blogage.de/entries/2009/7/13/----1].[/url][url=http://showsale.uniterre.com/94210/%E6%84%9B%E9%9B%A2%E5%88%A5%E5%9B%9E%E6%86%B6.html].[/url][url=http://showsale.tumblr.com/post/139453271].[/url][url=http://sale09.createblog.com/blog/entry.php?id=25513].[/url][url=http://sale09.namjai.cc/e11187.html].[/url][url=http://sale09.ti-da.net/e2493713.html].[/url][url=http://sale09.i-yoblog.com/e184028.html].[/url][url=http://sale09.da-te.jp/e194597.html].[/url][url=http://sale09.blog.lu/post/706/3718].[/url][url=http://blog.bitcomet.com/goodshow/post_102458/].[/url][url=http://showsale.blog.com/2009/07/11/life/].[/url][url=http://hk.myblog.yahoo.com/linsale18/article?mid=2].[/url][url=http://sale0909.spaces.live.com/blog/cns%21B9BB131DA7A2ECC6%21116.entry].[/url][url=http://sale09.mysinablog.com/index.php?op=ViewArticle&articleId=1818259].[/url][url=http://showsale.blog126.fc2.com/blog-entry-2.html].[/url][url=http://blog.qooza.hk/sale09?eid=14150311].[/url][url=http://showsale.ycool.com/post.3413063.html].[/url][url=http://blog.sina.com.tw/showsale/article.php?pbgid=84400&entryid=595625].[/url][url=http://diary.blog.yam.com/showsale/article/7435341].[/url][url=http://showsale.blogspot.com/2009/07/blog-post.html].[/url][url=http://sale09.pixnet.net/blog/post/26299083].[/url][url=http://tw.myblog.yahoo.com/linsale18/article?mid=1].[/url][url=http://www.wretch.cc/blog/linsale18/454178].[/url][url=http://www.33db.com/index.php?op=ViewArticle&articleId=18&blogId=8].[/url][url=http://blog.xuite.net/sale09/blog/25322438].[/url][url=http://sale09.blog.ithome.com.tw/post/2222/28483].[/url][url=http://fashionshow99.blogspot.com/2009/07/blog-post.html].[/url][url=http://hi.fdlive.com/node/12091].[/url][url=http://fashionshow99.xanga.com/706854819/263771996831278822028165285008221/].[/url][url=http://blog.sina.com.tw/fashionshow/article.php?pbgid=84417&entryid=586153].[/url][url=http://meco.namjai.cc/e11149.html].[/url][url=http://blog.qooza.hk/fashionshow?eid=14148467].[/url][url=http://blog.yam.com/fashionshow99/article/22591032].[/url][url=http://hk.myblog.yahoo.com/memegoli/article?mid=1].[/url][url=http://blog.bitcomet.com/fashionshow/post_102364/].[/url][url=http://tw.myblog.yahoo.com/memegoli/article?mid=1].[/url][url=http://fashionshow99.spaces.live.com/blog/cns%211C8FBE4D48B94A43%21122.entry].[/url]

页: [1]


Powered by Discuz! Archiver 5.0.0  © 2001-2006 Comsenz Inc.