函数返回记录与界面字段 [英] Function returning record with interface field
问题描述
在请求关于记录中的界面字段的问题后,我认为以下内容将起作用(注意断言):
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屋!