匿名方法 - 变量捕获与值捕获 [英] Anonymous methods - variable capture versus value capture

查看:17
本文介绍了匿名方法 - 变量捕获与值捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是基于第 1 部分匿名方法部分中的示例的 SSCCEChris Rolliston 出色的 Delphi XE2 Foundations 书籍,关于变量的概念捕获(其中的任何错误完全取决于我).

它完全按照我的预期工作,连续点击 666、667、668、669BtnInvoke 按钮.特别是它很好地说明了捕获版本的局部变量 I 在 btnSetUpClick 退出后仍然存在很长时间.

到目前为止一切顺利.我要问的问题不在于这段代码本身,而是在于艾伦·鲍尔 (Allen Bauer) 的博客中所说的话:

http://blogs.embarcadero.com/abauer/2008/10/15/38876

现在,我知道最好不要与老板争论,所以我确定我没有抓住要点他在变量捕获和价值捕获之间进行了区分.以我的简单方式观察它,我的基于 CR 的示例通过将 I 捕获为变量来捕获 I 的值.

那么,我的问题是,鲍尔先生试图描绘的区别究竟是什么?

(顺便说一句,尽管每天观看 SO 的 Delphi 部分长达 9 个月以上,但我仍然不完全清楚这个 q 是否是主题.如果没有,我很抱歉,我会将其删除.)

类型TAnonProc = 程序参考;无功P1,P2:TAnonProc;程序 TForm2.Log(Msg : String);开始Memo1.Lines.Add(Msg);结尾;程序 TForm2.btnSetUpClick(Sender: TObject);无功我:整数;开始我 := 41;P1 := 程序开始公司(一);日志(IntToStr(I));结尾;我 := 665;P2 := 程序开始公司(一);日志(IntToStr(I));结尾;结尾;过程 TForm2.btnInvokeClick(Sender: TObject);开始断言(已分配(P1));断言(已分配(P2));P1;P2;结尾;

解决方案

变量捕获 vs 值捕获非常简单.让我们假设两个匿名方法捕获同一个变量.像这样:

类型TMyProc = 程序引用;无功i:整数;P1、P2:TMyProc;....我:= 0;P1 := 程序开始 Writeln(i);公司(一);结尾;P2 := 程序开始 Writeln(i);公司(一);结尾;P1();P2();写入(i);

有一个变量被两种方法捕获.输出为:

<前>012

这是一个变量的捕获.如果该值被捕获,但实际上并没有被捕获,人们可能会想象这两种方法将具有以值 0 开头的单独变量.并且两个函数都可能输出 0.

在您的示例中,您应该想象 P1 捕获值 41,而 P2 捕获值 665.但这不会发生.只有一个变量.它在声明它的过程和捕获它的匿名方法之间共享.只要共享它的所有各方都存在,它就会存在.一方对变量所做的修改会被所有其他人看到,因为只有一个变量.

<小时>

因此,无法捕获值.要获得这种感觉,您需要将一个值复制到一个新变量中,并捕获该新变量.例如,这可以通过一个参数来完成.

function CaptureCopy(Value: Integer): TMyProc;开始结果 := 程序开始 Writeln(Value);结尾;结尾;...P3 := CaptureCopy(i);

这会将 i 的值复制到一个新变量中,即过程参数,并捕获它.i 的后续更改对 P3 没有影响,因为捕获的变量是 P3 的局部变量.

Below is a SSCCE based on an example in the Anonymous Methods section of Part 1 of Chris Rolliston's excellent Delphi XE2 Foundations book, about the idea of variable capture (any errors in it are entirely down to me).

It works exactly as I'd expect, logging 666, 667, 668, 669 on successive clicks of the BtnInvoke button. In particular it nicely illustrates how the captured version of the local variable I persists long after btnSetUpClick exits.

So far so good. The problem I'm asking about isn't with this code per se but with what's said in Allen Bauer's blog here:

http://blogs.embarcadero.com/abauer/2008/10/15/38876

Now, I know better than to argue with the boss, so I am sure I'm missing the point of the distinction he draws between variable capture and value capture. To my simple way of looking at it, my CR-based example captures the value of I by capturing I as a variable.

So, my question is, what is the distinction Mr Bauer is trying to draw, exactly?

(Btw, despite watching the Delphi section of SO daily for 9+ months, I'm still not entirely clear if this q is on-topic. If not, my apologies and I'll take it down.)

type
  TAnonProc = reference to procedure;

var
  P1,
  P2 : TAnonProc;

procedure TForm2.Log(Msg : String);
begin
  Memo1.Lines.Add(Msg);
end;

procedure TForm2.btnSetUpClick(Sender: TObject);
var
  I : Integer;
begin
  I := 41;
  P1 := procedure
    begin
      Inc(I);
      Log(IntToStr(I));
    end;

  I := 665;
  P2 := procedure
    begin
      Inc(I);
      Log(IntToStr(I));
    end;
end;

procedure TForm2.btnInvokeClick(Sender: TObject);
begin
  Assert(Assigned(P1));
  Assert(Assigned(P2));

  P1;
  P2;
end;

解决方案

Variable capture vs value capture is simple enough. Let us suppose that two anonymous methods capture the same variable. Like this:

Type
  TMyProc = reference to procedure;
var
  i: Integer;
  P1, P2: TMyProc;
....
i := 0;
P1 := procedure begin Writeln(i); inc(i); end;
P2 := procedure begin Writeln(i); inc(i); end;
P1();
P2();
Writeln(i);

There is a single variable that is captured by both methods. The output is:

0
1
2

This is capture of a variable. If the value was captured, which it isn't, one might imagine that the two methods would have separate variables that both started with value 0. And both functions might output 0.

In your example, you are supposed to imagine that P1 captures the value 41, and P2 captures the value 665. But that does not happen. There is exactly one variable. It is shared between the procedure that declares it, and the anonymous methods that capture it. It lives as long as all parties that share it live. Modifications to the variable made by one party are seen by all others because there is exactly one variable.


So, it is not possible to capture a value. To get behaviour that feels like that you need to copy a value to a new variable, and capture that new variable. That can be done with, for instance, a parameter.

function CaptureCopy(Value: Integer): TMyProc;
begin
  Result := procedure begin Writeln(Value); end;
end;

...
P3 := CaptureCopy(i);

This will copy the value of i into a new variable, the procedure parameter, and capture that. Subsequent changes to i have no influence on P3 because the captured variable is local to P3.

这篇关于匿名方法 - 变量捕获与值捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆