Funkcja
function ReturnRec: TRec<Integer>;
jest semantycznie równa procedury
procedure ReturnRec(var Result: TRec<Integer>);
[Jestem pewien, że ktoś z Embarcadero, prawdopodobnie Barry Kelly czy Alan Bauer stwierdził to gdzieś, ale nie mogę znaleźć referencja w tej chwili.]
W drugim przypadku kompilator zakłada, że rekord zostanie zainicjowany (w razie potrzeby), zanim zostanie przekazany do ReturnRec i nie tworzy żadnego kodu inicjalizacyjnego dla rec wewnątrz ReturnRec. Zakładam, że ta sama ścieżka kodowa wewnątrz kompilatora jest brana dla pierwszego przykładu i dlatego Wynik nie jest inicjowany.
Zresztą, rozwiązanie jest proste:
function TTestClass.ReturnRec : TRec <Integer>;
begin
Result.Intf := TInterfacedObject.Create;
end;
Wystarczy założyć, że kompilator nie wie, co robi i przypisać interfejs i wszystko będzie działać dobrze.
EDIT
Problem masz wystąpi z pętli 'for'. Kod
for I := 1 to 1000 do
Rec := Test.ReturnRec;
jest kompilowany do czegoś takiego:
var
result: TRec<Integer>;
Initialize(result);
for I := 1 to 1000 do begin
Test.ReturnRec(result);
rec := result;
end;
Dlatego jesteś ponowne sam rekord całego i dlatego Result.Intf jest niezainicjowany tylko za pierwszym razem.
EDIT2
Można oszukać kompilator przesuwając t.ReturnRec zawołać z pętli do oddzielnego metody.
procedure GetRec(t: TTest; var rec: TRec);
begin
rec := t.ReturnRec;
end;
for i := 1 to 1000 do
GetRec(t, rec);
Teraz ukryta zmienna wyników żyje w procedurze GetRec i jest inicjowana za każdym razem, gdy wywoływana jest metoda GetRec.
Czy asercja kończy się niepowodzeniem podczas pierwszego lub drugiego uruchomienia pętli? – Johan
@Smasher FWIW, to jest to o czym myślałem, kiedy napisałem moją błędną odpowiedź: http://stackoverflow.com/questions/5102843/delphi-function-result-nottedempted-during-for-loop –