內聯變量聲明(Inline Variable Declaration)是Delphi Rio 10.3中引入的功能。它是什么?
簡而言之,可以在代碼的任何行中聲明一個變量。也就是說,您可以在begin..end塊中以這種方式聲明變量:
procedure Test;
begin
var I: Integer;
I := 22;
ShowMessage (I.ToString);
end;
許多人已經了解了此功能的工作原理,但不了解為什么它很有趣。在本文中,我將向您展示此新功能,重點介紹其帶來的優勢。
1.整理您的代碼
該變量只能從聲明點訪問。對於許多人來說,這更好地組織在一個大的方法中的代碼,因為它可以更好地了解那里正在使用的變量。考慮以下代碼:
procedure Test;
var
A, B, C, D, E: Integer;
Found, Done, Excluded: Boolean;
Text: string;
begin
// many
// lines
// of
// code
end;
了解所有這些變量的使用位置,初始化時間,是否在之前設置了值等可能令人困惑。在下面的代碼中,我們知道Text變量例如不存在於代碼的開頭,並且僅在結尾使用。在該部分代碼之前,沒有代碼會更改其值:
procedure Test;
begin
var A, C: Integer;
// We cannot use Text here
// lines
// of
// code
var Text: string;
// Text can only be used here
end;
2.盡量減少錯誤
您是否曾經做過這樣的事情:
procedure Test;
var I: Integer;
begin
for I := 0 to Count - 1 do
Process;
DoSomethingWithI(I);
end;
也就是說,在循環結束后使用for變量。這是不安全的,盡管編譯器對此發出警告,但許多人忽略了它。通過聲明for變量內聯,它將僅在for內有效,而在塊外使用它將導致編譯錯誤:
procedure Test;
begin
for var I: Integer := 0 to Count - 1 do
Process;
DoSomethingWithI(I); // Compile error!!!
end;
上面的代碼的好處在於,變量的范圍僅限於聲明它們的塊。這樣可以最大程度地減少出錯的機會。例如,假設您有如下代碼:
procedure Test;
var I: Integer;
begin
I := CalculateSomething;
Persist(I);
// many lines below...
Log(I);
end;
然后,您最終需要以第一部分僅在指定條件下執行的方式重構代碼。您認為該變量I僅在此處使用,並執行以下操作:
procedure Test;
var I: Integer;
begin
if Condition then
begin
I := CalculateSomething;
Persist(I);
end;
// many lines below...
Log(I);
end;
在那里,您忘記了最后一行,也許I的值不是您所期望的。如果在塊外使用變量,則將變量的范圍更改為塊會產生編譯錯誤,這將立即向您顯示問題,因此您可以做出決定:
procedure Test;
begin
if Condition then
begin
var I: Integer;
I := CalculateSomething;
Persist(I);
end;
// many lines below...
Log(I); // Compile error!
end;
3.打字少
誰不希望提高生產力?如果可以少鍵入一些內容來聲明變量,為什么不呢?現在,您可以同時聲明和初始化變量:
procedure Test;
begin
var I: Integer := 22;
ShowMessage (I.ToString);
end;
但不僅如此。還有一個類型推斷,這意味着在大多數情況下,在聲明它時不需要包括變量類型。只需使用值初始化變量,Delphi就會知道變量類型。
看起來沒什么大不了的?想象一下一個變量類型使用大量泛型的情況:
procedure NewTest;
var
MyDictionary: TObjectDictionary<string, TObjectList<TMyAmazingClass>>;
Pair: TPair<string, TObjectList<TMyAmazingClass>>;
List: TObjectList<TMyAmazingClass>;
begin
MyDictionary := TObjectDictionary<string, TObjectList<TMyAmazingClass>>.Create;
MyDictionary.Add('one', CreateList);
Pair := MyDictionary.ExtractPair('one');
List := Pair.Value;
ShowMessage(List.Count.ToString);
end;
使用內聯變量和類型推斷,您可以通過以下方式重寫代碼:
procedure NewTest;
begin
var MyDictionary := TObjectDictionary<string, TObjectList<TMyAmazingClass>>.Create;
MyDictionary.Add('one', CreateList);
var Pair := MyDictionary.ExtractPair('one');
var List := Pair.Value;
ShowMessage(List.Count.ToString);
end;
更好,不是嗎?
4.提高性能
變量屬於更有限范圍的事實(在begin..end塊內)甚至可以提高代碼性能!
您可以在這篇出色的文章中看到更多詳細信息:內聯變量可以提高性能。概括來說:僅當代碼執行進入塊時,變量才會初始化;僅在塊退出時,變量才會最終確定。在此代碼中,例如:
procedure TestInlineVars(const ACondition: Boolean);
begin
// BEFORE
if (ACondition) then
begin
var S := 'Inline String';
var I: IInterface := TInterfacedObject.Create;
var F: TFoo;
F.S := 'Managed Record';
end;
// AFTER
end;
變量S,I和F是托管類型(字符串,接口和記錄)。編譯器會自動為其添加初始化和完成代碼。
如果您調用TestInlineVars過程一百萬次,將會產生很大的影響。但是,使用上面的代碼,只有在 ACondition為true並且實際執行該塊的情況下,變量才會被初始化。減少不必要的代碼被執行。
5.使使用條件指令更容易
此功能甚至可以在小事情上提供幫助。本文引起了我的注意:內聯變量的意外好處:條件塊。
如果使用編譯器偽指令在每種情況下聲明並使用不同的變量,則還需要在編譯器偽指令周圍包裝變量聲明:
procedure DoesSomething;
var
{$IFDEF CASE1}
var1: Integer;
{$ENDIF}
{$IFDEF CASE2}
var2: Integer;
{$ENDIF
begin
{$IFDEF CASE1}
// use var1
{$ENDIF}
{$IFDEF CASE2}
// use var2
{$ENDIF}
end;
無聊吧?我認為這更容易:
procedure DoesSomething;
begin
{$IFDEF CASE1}
var1: Integer;
// use var1
{$ENDIF}
{$IFDEF CASE2}
var2: Integer;
// use var2
{$ENDIF}
end;
我認為,內聯變量在未在此處列出的特定情況下仍會帶來其他細微的好處。如果您認為還有其他好處,請發表評論。如果您不同意並且認為內聯變量對於Delphi不是好消息,請也發表您的評論。只是不要忘記一件事:如果您不喜歡它,那就不要使用它!
原文:https://landgraf.dev/en/5-reasons-to-use-inline-variables-in-delphi/