delphi – 带有接口字段的函数返回记录

前端之家收集整理的这篇文章主要介绍了delphi – 带有接口字段的函数返回记录前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在询问 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创建任何初始化代码.我假设第一个例子中的编译器内部使用了相同的代码路径,这就是为什么Result没有初始化的原因.

无论如何,解决方案很简单:

function TTestClass.ReturnRec : TRec <Integer>;
begin
  Result.Intf := TInterfacedObject.Create;
end;

假设编译器知道它在做什么并分配接口,一切都会正常工作.

编辑

您遇到的问题来自’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只是第一次未初始化.

EDIT2

您可以通过将循环中的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相关文章