【问题标题】:E2555 Cannot capture symbol 'Self'E2555 无法捕获符号“Self”
【发布时间】:2019-06-06 07:58:21
【问题描述】:

当我运行以下代码时,我得到E2555 Cannot capture symbol 'Self'

type
  TLookupTable = record
    FData: TArray<TOtherRec>;
    procedure ReverseLeftToRight;
  end;

procedure TLookupTable.ReverseLeftToRight;
begin
  Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
    FData[i]:= FData[i].ReverseLeftRight;
  end); {for i}
end;

我该如何解决这个问题?

【问题讨论】:

    标签: delphi anonymous-methods


    【解决方案1】:

    问题是var 参数(包括Self 的隐藏var 参数)没有被捕获。但是我们不想复制记录,那是没有用的,因为那样我们的方法就行不通了。

    使隐藏的self 参数显式化的技巧。
    如果它是一个类,那么很容易 (var S:= Self),如果不是,你必须声明一个指向你的记录的指针。

    procedure TLookupTable.ReverseLeftToRight;
    type 
      PLookupTable = ^TLookupTable;
    var
      S: PLookupTable;
    begin
      S:= @Self;
      Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
        S.FData[i]:= S.FData[i].ReverseLeftRight;
      end); {for i}
    end;
    

    现在编译器不再抱怨了。
    (请注意,我使用S^.xyz 的隐式语法)。

    德尔福里约
    使用如下所示的内联 var 声明是行不通的。

      //S: PLookupTable;
    begin
      var S:= @Self; //inline declaration
      Parallel.For(0, Length(FData)-1).NoWait.Execute(procedure(i: integer) begin
        S.FData[i]:= S.FData[i].ReverseLeftRight;
      end); {for i}
    

    这会生成:E2018 Record, object or class type required
    我猜内联 @Self 被解析为通用指针,这很遗憾,因为有足够的信息来推断内联变量的正确类型。

    异步问题
    如果您使用异步 (.NoWait) 线程/任务执行代码,那么最好将 FData 放在局部变量中。 FData 作为一个动态数组,已经是一个指针(所以不会发生复制,只是一个引用计数)。并且动态数组没有 Copy-on-Write 语义,因此原始数组会得到更新。
    照原样,Self 记录可能会在代码运行时超出范围,从而导致访问冲突(或更糟)。

    【讨论】:

    • 就我个人而言,我宁愿将FData 放入一个局部变量中并捕获它。如果闭包异步执行,这也可以确保捕获的Self 不会超出范围。
    • @StefanGlienke,说得好,我一直忘记动态数组不是 CoW。
    猜你喜欢
    • 2023-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-09
    • 2015-03-24
    • 2016-04-05
    • 2015-01-28
    相关资源
    最近更新 更多