询问后this question about interface fields in records我假设以下内容可行(注意断言):
type
TRec <T> = record
Intf : IInterface;
end;
TTestClass = class
public
function ReturnRec : TRec <Integer>;
end;
// Implementation
function TTestClass.ReturnRec : TRec <Integer>;
begin
Assert (Result.Intf = nil); // Interface field in record should be initialized!
Result.Intf := TInterfacedObject.Create;
end;
我使用以下代码对此进行了测试:
for I := 1 to 1000 do
Rec := Test.ReturnRec;
断言失败!
我的错误在哪里?什么假设是错误的?
最佳答案
功能
function ReturnRec: TRec<Integer>;
语义上等于过程
procedure ReturnRec(var Result: TRec<Integer>);
[我很确定来自 Embarcadero 的人,可能是 Barry Kelly 或 Alan Bauer 在某处说过这一点,但我目前找不到引用资料。]
在第二种情况下,编译器假定记录在传递给 ReturnRec 之前将被初始化(如果需要),并且不会在 ReturnRec 内为 rec 创建任何初始化代码。我假设第一个示例采用编译器内相同的代码路径,这就是结果未初始化的原因。
无论如何,解决方案很简单:
function TTestClass.ReturnRec : TRec <Integer>;
begin
Result.Intf := TInterfacedObject.Create;
end;
假设编译器知道它在做什么并分配接口(interface),一切都会正常工作。
编辑
您遇到的问题是由“for”循环引起的。您的代码
for I := 1 to 1000 do
Rec := Test.ReturnRec;
被编译成这样的东西:
var
result: TRec<Integer>;
Initialize(result);
for I := 1 to 1000 do begin
Test.ReturnRec(result);
rec := result;
end;
这就是为什么您要重复使用相同的记录,这就是为什么 Result.Intf 仅在第一次时未初始化。
编辑2
您可以通过将 t.ReturnRec 调用从循环移出到单独的方法中来欺骗编译器。
procedure GetRec(t: TTest; var rec: TRec);
begin
rec := t.ReturnRec;
end;
for i := 1 to 1000 do
GetRec(t, rec);
现在,隐藏的结果变量位于 GetRec 过程中,并在每次调用 GetRec 时进行初始化。
关于delphi - 返回带有接口(interface)字段的记录的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8518992/