Ste*_*eve 29 delphi closures anonymous-methods
德尔福2009,在一些很酷的东西,也刚刚得到匿名方法.我已经看过这些示例,以及关于匿名方法的博客文章,但我还没有得到它们.有人可以解释为什么我应该兴奋吗?
Too*_*the 16
请看一下封口.
Delphi匿名函数是闭包.
这些是在其他函数中创建的,因此可以访问该函数的范围.如果将anonumous函数分配给在调用原始函数后调用的函数参数,则情况更是如此.(我稍后会创建一个例子).
type
TAnonFunc = reference to procedure;
TForm2 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
F1 : TAnonFunc;
F2 : TAnonFunc;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
a : Integer;
begin
a := 1;
F1 := procedure
begin
a := a + 1;
end;
F2 := procedure
begin
Memo1.Lines.Add(IntToStr(a));
end;
end;
Run Code Online (Sandbox Code Playgroud)
上述方法将两个匿名函数分配给字段F1和F2.第一个增加局部变量,第二个显示变量的值.
procedure TForm2.Button2Click(Sender: TObject);
begin
F1;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
F2;
end;
Run Code Online (Sandbox Code Playgroud)
您现在可以调用这两个函数,并且它们可以访问相同的a.因此,调用F1两次,F2调用一次3.当然这是一个简单的例子.但它可以扩展到更有用的代码.
在多线程环境中,可以在对Synchronize的调用中使用匿名函数,这样就无需使用无数方法.
Oli*_*sen 12
只需考虑典型的回调代码,您需要将数据提供给回调.通常需要回调该数据只,但你必须通过一些箍跳得到它那里,而不必辞职未OOP的做法就像全局变量.使用匿名方法,数据可以保持原样 - 您不必不必要地扩展其范围或将其复制到某个辅助对象.只需将您的回调代码作为匿名方法就地编写,它可以完全访问和操作定义匿名方法的站点上的所有局部变量(而不是它被调用的位置!).
匿名方法还有其他方面,最明显的是它们是,好吧:匿名,但这是真正使它们为我"点击"的那个...
Uwe*_*abe 11
也许这个例子可以为你带来一些价值.在这里,我将实现一个可缩放的显示列表,用于在TCanvas上绘制而不声明不同类型的显示类.它也大量使用泛型.假设我们有一个带有TPaintBox和TTrackBar的TForm ......
type
TDisplayProc = TProc<TCanvas>;
type
TFrmExample3 = class(TForm)
pbxMain: TPaintBox;
trkZoom: TTrackBar;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure pbxMainClick(Sender: TObject);
procedure pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure pbxMainPaint(Sender: TObject);
procedure trkZoomChange(Sender: TObject);
private
FDisplayList: TList<TDisplayProc>;
FMouseX: Integer;
FMouseY: Integer;
FZoom: Extended;
procedure SetZoom(const Value: Extended);
protected
procedure CreateCircle(X, Y: Integer);
procedure CreateRectangle(X, Y: Integer);
function MakeRect(X, Y, R: Integer): TRect;
public
property Zoom: Extended read FZoom write SetZoom;
end;
implementation
{$R *.dfm}
procedure TFrmExample3.PaintBox1Paint(Sender: TObject);
var
displayProc: TDisplayProc;
begin
for displayProc in FDisplayList do
displayProc((Sender as TPaintBox).Canvas);
end;
procedure TFrmExample3.CreateCircle(X, Y: Integer);
begin
FDisplayList.Add(
procedure (Canvas: TCanvas)
begin
Canvas.Brush.Color := clYellow;
Canvas.Ellipse(MakeRect(X, Y, 20));
end
);
end;
procedure TFrmExample3.CreateRectangle(X, Y: Integer);
begin
FDisplayList.Add(
procedure (Canvas: TCanvas)
begin
Canvas.Brush.Color := clBlue;
Canvas.FillRect(MakeRect(X, Y, 20));
end
);
end;
procedure TFrmExample3.FormCreate(Sender: TObject);
begin
FDisplayList := TList<TDisplayProc>.Create;
end;
procedure TFrmExample3.FormDestroy(Sender: TObject);
begin
FreeAndNil(FDisplayList);
end;
function TFrmExample3.MakeRect(X, Y, R: Integer): TRect;
begin
Result := Rect(Round(Zoom*(X - R)), Round(Zoom*(Y - R)), Round(Zoom*(X + R)), Round(Zoom*(Y + R)));
end;
procedure TFrmExample3.pbxMainClick(Sender: TObject);
begin
case Random(2) of
0: CreateRectangle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
1: CreateCircle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
end;
pbxMain.Invalidate;
end;
procedure TFrmExample3.pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
FMouseX := X;
FMouseY := Y;
end;
procedure TFrmExample4.SetZoom(const Value: Extended);
begin
FZoom := Value;
trkZoom.Position := Round(2*(FZoom - 1));
end;
procedure TFrmExample4.trkZoomChange(Sender: TObject);
begin
Zoom := 0.5*(Sender as TTrackBar).Position + 1;
pbxMain.Invalidate;
end;
Run Code Online (Sandbox Code Playgroud)
人们已经提供了代码,所以我只列出一些有用的地方.
假设你有一些GUI代码.通常,对于像按钮的onclick处理程序这样的东西,你必须提供一个在单击该按钮时调用的函数.但是,让我们说这个功能必须做的就像弹出一个消息框或在某个地方设置一个字段一样简单.假设您的代码中有几十个按钮.如果没有匿名函数,你将不得不拥有大量名为"OnButton1Click","OnExitButtonClick"等的函数,它们可能会使你的代码混乱......或者你可以创建立即附加到这些事件的匿名函数,并且你不要再也不用担心了.
另一个用途是函数式编程.假设您有一个数字列表.你想只找回那些可以被三整除的数字.可能有一个函数调用filter
,它接受一个返回布尔值和列表的函数,并返回一个新列表,该列表仅包含第一个列表中的那些元素,当传递给函数时,返回True.例:
filter(isOdd, [1, 2, 3, 5, 6, 9, 10]) --> [1, 3, 5, 9]
Run Code Online (Sandbox Code Playgroud)
被迫定义一个函数"isDivisibleByThree"然后将它传递给过滤器会很烦人,所以这里匿名函数的另一个用途就是快速创建一个你不需要的函数并将其传递给过滤器.
归档时间: |
|
查看次数: |
7344 次 |
最近记录: |