インライン変数宣言

提供: RAD Studio
移動先: 案内検索

10.3 の Delphi 言語では、ローカル変数の宣言においてさらなる柔軟性が提供されています。 これまで、伝統的な Pascal 言語の規約に従い、すべての変数は、関数、プロシージャ、メソッドのコードの開始前に記述される、var ブロックで行われる必要がありました。

procedure Test;
var
  I: Integer;
begin
  I := 22;
  ShowMessage (I.ToString);
end;

新しいインライン変数宣言の構文により、コード ブロック内で直接変数を宣言できるようになりました(また、通常通り、複数のシンボルも可):

procedure Test;
begin
  var I: Integer;
  I := 22;
  ShowMessage (I.ToString);
end;

procedure Test2;
begin
  var I, K: Integer;
  I := 22;
  K := I + 10;
  ShowMessage (K.ToString);
end;

一部に限定された変更のように感じられるかもしれませんが、この変更には複数の効果があります。 1 つは、宣言と初期化が 1 つの文の中で行われるということです。 2 つめは、複雑なコード ブロック内で必要に応じて、スコープを限定して変数を宣言できるという点です(変数は、その宣言した位置からのみ可視になるため、変数を宣言しておく必要はなく、コードの一部に対しては初期化されません)。

インライン変数のスコープ

3 つの効果は、宣言が第2レベルの begin-end ブロック内でも宣言することができ、スコープはそのブロック内に限定できるという点です。

procedure Test; // declaration and initialization in a single statement
begin
  var I: Integer := 22;
  ShowMessage (I.ToString);
end;

procedure Test1; // multiple inline declarations (symbols declared when used)
begin
  var I: Integer := 22;
  var J: Integer;
  J := 22 + I;
  var K: Integer := I + J;
  ShowMessage (K.ToString);
end;

procedure Test2; // scope limited to local block
begin
  var I: Integer := 22;
  if I > 10 then
  begin
    var J: Integer := 3;
    ShowMessage (J.ToString);
  end
  else
  begin
    var K: Integer := 3;
    ShowMessage (J.ToString); // COMPILER ERROR: “Undeclared identifier: ‘J’”
  end;
end;

上のコード スニペットにみられるよう、begin-end ブロックで宣言された変数は、特定のブロック内でのみ可視になり、ブロックが終了した後には見えなくなります。 if 文の終わりでは、J と K は可視ではなくなっています。

効果は、可視性に限定されません。 管理されている変数(インターフェイスのリファレンスやレコードなど)は、プロシージャやメソッドの終わりではなく、ブロックの終わりで適切にクリーンアップされます:

procedure Test99;
begin

  // some code

  if (something) then
  begin
    var Intf: IInterface = GetInterface; // Intf.AddRef
    var MRec: TManagedRecord = GetMRecValue; // MRec.Create + MRec.Assign
    UseIntf(Intf);
    UseMRec(MRec);
  end; // Intf.Release and MRec.Destroy are implicitly called at end of scope
  
  // more code

end; // no additional cleanup

インライン変数の型推論

さらに、コンパイラはいくつかの状況下で、int 行宣言の場所で、変数の型を、それに割り当てられる値の型を見ることで、推測できるようになりました。

procedure Test;
begin
  var I := 22;
  ShowMessage (I.ToString);
end;

右辺の値式の型(つまり、:= の後にくるもの)は、その変数の型を判別するために解析されます。  データ型によっては、上の例での、数値 22(ShortInt)が Integer に拡張されているように、より大きい型へ「拡張」されます。 一般的なルールと同様、普遍の式の型が整数型でかつ 32 ビットより小さい場合、変数は 32 ビット整数として宣言されます。 特定の、より小さい数値型を望む場合には、明示的な型を使用することができます。

また、値の型なしで宣言できるのは、1 つの識別子のみです(一般的な変数宣言やインライン宣言とは異なります)。

この機能により、Interger や文字列に対しては、2-3 のキーストロークの手間を省く一方で、ジェネリック型のインスタンスのような複合型の場合では、変数の型推論はかなり便利なものとなります。 以下のコード スニペットでの推論される型は、変数 MyDictionary に対しては “TDictionary<string, Integer>”、変数 APair に対しては “TPair<string, Integer>” です。

procedure NewTest;
begin
  var MyDictionary := TDictionary<string, Integer>.Create;
  MyDictionary.Add ('one', 1);
  var APair := MyDictionary.ExtractPair('one');
  ShowMessage (APair.Value.ToString)
end;

インライン定数

変数のほかに、定数値の宣言もインライン化することができるようになりました。 これは、型が推論される場合(長いこと定数に対してはこの機能は利用可能でした)、型定数や型なし定数に適用できます。 シンプルな例は以下のとおりです。

   const M: Integer = (L + H) div 2; // single identifier, with type specifier
   const M = (L + H) div 2; // single identifier, without type specifier

変数宣言を伴う for ループ

インライン変数宣言の利点を生かせる特殊な状況の 1 つに、ループ文(for-to ループや for-in ループ)があります。

  for var I: Integer := 1 to 10 do ...
  for var Item: TItemType in Collection do...

型推論を利用することで、コードはさらにシンプルにすることができます:

  for var I := 1 to 10 do ...
  for var Item in Collection do ...

これは、以下のサンプル コードのように、限定されたスコープを持つ変数の場合、特に有効です。 ループの外で ‘I’変数を使用すると、コンパイラ エラーが発生します(これは今までは大抵の場合、警告のみでした)。

procedure ForTest;
begin
  var total := 0;
  for var I: Integer := 1 to 10 do
    Inc (Total, I);
  ShowMessage (total.ToString);
  ShowMessage (I.ToString); // compiler error: Undeclared Identifier ‘I’