Déclaration de variable inline

De RAD Studio
Aller à : navigation, rechercher

Dans 10.3, le langage Delphi permet une plus grande souplesse dans la déclaration des variables locales. Jusqu'à maintenant, en conformité avec les règles du langage Pascal, toutes les déclarations de variables devaient être effectuées dans un bloc var qui était écrit avant le début d'une fonction, d'une procédure ou d'une méthode.

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

La nouvelle syntaxe de déclaration des variables inline vous permet de déclarer la variable directement dans un bloc de code (tout en permettant d'utiliser plusieurs symboles).

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;

Même si c'est un changement limité, il convient de signaler quelques effets secondaires. La déclaration et l'initialisation peuvent être effectuées dans une seule instruction. Vous pouvez déclarer des variables dans un bloc de code complexe avec une portée limitée (la variable est uniquement visible depuis l'emplacement de sa déclaration et il n'est pas nécessaire qu'elle soit déclarée et non initialisée pour la portion de code).

Portée des variables inline

Il existe un troisième effet secondaire : la déclaration est également autorisée au sein du bloc begin-end de deuxième niveau, la portée étant limitée à ce bloc.

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;

Comme vous pouvez le voir dans le dernier extrait de code ci-dessus, une variable déclarée à l'intérieur d'un bloc begin-end n'est visible qu'au sein de ce bloc spécifique, et ne l'est plus une fois le bloc terminé. A la fin des instructions if, J et K ne seront plus visibles.

L'effet secondaire ne se limite pas uniquement à la visibilité. Une variable managée, comme une référence d'interface ou un enregistrement, sera correctement nettoyée à la fin du bloc, plutôt qu'à la fin d'une procédure ou d'une méthode :

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

Inférence de type pour les variables inline

De plus, le compilateur peut désormais inférer dans certaines circonstances le type d'une variable à l'emplacement de sa déclaration inline en examinant le type de la valeur qu'on lui a assigné.

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

Le type de l'expression r-value (plus exactement, ce qui apparaît après  :=) est analysé pour déterminer le type de la variable. Certains des types de données sont “développés” vers un type plus large. Ainsi dans l'exemple ci-dessus, la valeur numérique 22 (un ShortInt) est développée en entier (Integer). En règle générale, le type de l'expression située à droite est un type entier et est inférieur à 32 bits, la variable sera déclarée comme un entier 32 bits. Vous pouvez utiliser un type explicite si vous voulez un type spécifique, numérique et inférieur.

Sachez également que seul un identificateur unique peut être déclaré sans type de valeur (à la différence des déclarations de variables générales et des déclarations inline).

Alors que cette fonctionnalité peut vous faire économiser quelques frappes de touche pour un entier ou une chaîne, l'inférence de type de variable peut s'avérer être très pratique pour les types complexes comme les instances de types génériques. Dans l'extrait de code ci-dessous, les types inférés sont “TDictionary<string, Integer>” pour la variable MyDictionary et “TPair<string, Integer>” pour la variable APair.

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

Constantes inline

En plus des variables, il est désormais possible de définir une déclaration de valeur constante comme étant inline. Cela s'applique aux constantes de types ou aux constantes non typées. Dans ce cas, le type est inféré (une fonctionnalité qui existe depuis longtemps pour les constantes). Voici un exemple :

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

Pour les boucles avec une déclaration de variable

Les déclarations de variable inline s'avèrent particulièrement pratiques dans les instructions de boucle, y compris les boucles for-to et les boucles for-in.

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

Vous pouvez simplifier le code en tirant parti de l'inférence de type :

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

Voici une situation dans laquelle l'utilisation d'une variable avec une portée limitée présente un grand intérêt, comme dans l'extrait de code ci-dessous : l'utilisation de la variable ‘I’ à l'extérieur de la boucle provoque une erreur du compilateur (alors qu'auparavant cela provoquait simplement un avertissement) :

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’