函数返回记录与界面字段 [英] Function returning record with interface field

查看:139
本文介绍了函数返回记录与界面字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在请求关于记录中的界面字段的问题后,我认为以下内容将起作用(注意断言):

  type 
TRec< T> = record
Intf:IInterface;
结束

TTestClass = class
public
function ReturnRec:TRec< Integer> ;;
结束

//实现
函数TTestClass.ReturnRec:TRec< Integer> ;;
begin
Assert(Result.Intf = nil); //记录中的接口字段应该被初始化!
Result.Intf:= TInterfacedObject.Create;
结束

我使用以下代码进行了测试:

 为I:= 1到1000 do 
Rec:= Test.ReturnRec;

,断言失败!



我的错误在这里?什么假设是错误的?

解决方案

功能

 函数ReturnRec:TRec< Integer> ;; 

语义上等于程序

  procedure ReturnRec(var Result:TRec< Integer>); 

[我很确定Embarcadero的某个人,可能是Barry Kelly或Alan Bauer,我现在找不到参考。]



在第二种情况下,编译器假定在传递记录之前将被初始化(如有必要) ReturnRec并且不在ReturnRec中创建rec的任何初始化代码。我假设编译器中的代码路径与第一个示例相同,这就是为什么没有初始化Result。



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

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

只要假设编译器知道它在做什么,分配接口,一切都会正常工作。 p>

编辑



您从for循环发生的问题。您的代码

 为I:= 1到1000 do 
Rec:= Test.ReturnRec;

被编译成如下:

  var 
result:TRec< Integer> ;;

初始化(结果);
为I:= 1到1000 do begin
Test.ReturnRec(result);
rec:= result;
结束

这就是为什么你重复使用相同的记录,这就是为什么Result.Intf只被初始化第一次。



EDIT2



您可以通过将循环中的t.ReturnRec调用移至一个单独的方法。

 程序GetRec(t:TTest; var rec:TRec); 
begin
rec:= t.ReturnRec;
结束

for i:= 1到1000 do
GetRec(t,rec);

现在隐藏的结果变量存在于GetRec过程中,每次调用GetRec时都会初始化。 p>

After asking this question about interface fields in records I assumed that the following would work (notice the assertion):

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;

I tested this with the following code:

  for I := 1 to 1000 do
    Rec := Test.ReturnRec;

and the assertion fails!

Where's my mistake here? What assumption is wrong?

解决方案

Function

function ReturnRec: TRec<Integer>;

Is semantically equal to procedure

procedure ReturnRec(var Result: TRec<Integer>);

[I'm pretty sure that somebody from Embarcadero, probably Barry Kelly or Alan Bauer stated this somewhere but I can't find the reference at the moment.]

In the second case, the compiler assumes that the record will be initialized (if necessary) before it is passed to the ReturnRec and doesn't create any initialization code for rec inside ReturnRec. I'm assuming that the same code path inside compiler is taken for the first example and that's why the Result is not initialized.

Anyway, the solution is simple:

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

Just assume that compiler knows what it's doing and assign the interface and everything will work just fine.

EDIT

The problem you have occurs from the 'for' loop. Your code

for I := 1 to 1000 do
  Rec := Test.ReturnRec;

is compiled into something like this:

var
  result: TRec<Integer>;

Initialize(result);
for I := 1 to 1000 do begin
  Test.ReturnRec(result);
  rec := result;
end;

That is why you are reusing same record all over and that is why Result.Intf is uninitialized only the first time.

EDIT2

You can trick the compiler by moving t.ReturnRec call out from the loop into a separate method.

procedure GetRec(t: TTest; var rec: TRec);
begin
  rec := t.ReturnRec;
end;

for i := 1 to 1000 do
  GetRec(t, rec);

Now the hidden result variable lives in the GetRec procedure and is initialized every time GetRec is called.

这篇关于函数返回记录与界面字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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