Функция
function ReturnRec: TRec<Integer>;
Семантически равен процедуре
procedure ReturnRec(var Result: TRec<Integer>);
[Я почти уверен, что кто-то из Embarcadero, возможно, Барри Келли или Алан Бауэр, где-то говорил это, но я не могу найти ссылку на данный момент.]
Во втором случае компилятор предполагает, что запись будет инициализирована (при необходимости) до ее передачи в ReturnRec, и не создает никакого кода инициализации для rec внутри ReturnRec. Я предполагаю, что тот же путь кода внутри компилятора взят для первого примера, и поэтому Result не инициализируется.
В любом случае, решение простое:
function TTestClass.ReturnRec : TRec <Integer>;
begin
Result.Intf := TInterfacedObject.Create;
end;
Просто предположите, что компилятор знает, что он делает, и назначьте интерфейс, и все будет работать нормально.
EDIT
Проблема, с которой вы столкнулись, связана с циклом 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.