当我运行以下代码时,我得到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;
我该如何解决这个问题?
最佳答案
问题在于 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 需要记录、对象或类类型
。
我猜内联 @Self
被解析为通用指针,这很遗憾,因为有足够的信息来推断内联变量的正确类型。
异步问题
如果您使用异步 (.NoWait
) 线程/任务执行代码,那么最好将 FData
放入局部变量中。 FData 作为一个动态数组,已经是一个指针(因此不会发生复制,只是一个引用计数)。并且动态数组没有 Copy-on-Write 语义,因此原始数组将被更新。
事实上,在代码运行时,Self
记录可能会超出范围,因为指针操作 S:= @Self
不会导致 FData 上的引用计数增加)。这可能会导致访问冲突(或更严重)。
引用 FData 会导致其引用计数增加,这意味着它不能过早超出范围。
关于delphi - E2555 无法捕获符号 'Self',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54145783/