Usando o For In

Veremos neste artigo que o compilador do Delphi faz até “mágicas” com a introdução do comando for in. Vamos relembrar o uso do for to tradicional, para facilitar o entendimento do for in que será abordado na sequência.

Como sabemos, quando precisamos fazer uma varredura em uma coleção com o for to, criamos uma variável do tipo integer (mais usado), representamos o início com 0 (zero) e o fim com a propriedade Count do objeto que queremos “varrer”, para que a coleção seja percorrida do seu inicio ao seu fim, como mostra a Listagem 1.

Listagem 1. O tradicional for to.

var

  i: integer;

  strItem: string;

begin

  ListBox2.Clear;

  for i := 0 to ListBox1.Items.Count -1 do

  begin

    strItem := ListBox1.Items[i];

    ListBox2.Items.Add(strItem);

  end;

end;

Agora no Delphi 2005 foi implementado no compilador um novo tipo de laço, o for in, simplificando e enxugando a escrita da linguagem Delphi. Como funciona? Antes do inicio do for in, devemos declarar uma variável do tipo a dos itens da coleção, assim com cada loop no laço, está variável receberá o item corrente. A variável deve ser declarada dentro do mesmo bloco do for in e não pode ser modificada dentro do laço.

O for in se encarrega da varredura da coleção por completa, que é processada na ordem que estiver definida, começando do índice menor para o índice maior. Para usar o for in na construção de uma varredura de classe, a classe deve executar um teste padrão prescrito da coleção. Um tipo que execute o teste padrão da coleção e deva ter os seguintes atributos:

  • A classe deve conter um método público do chamado GetEnumerator. O método GetEnumerator deve retornar uma classe, uma interface ou um tipo record;
  • A classe, interface ou record retornado por GetEnumerator deve conter um método público chamado MoveNext, que retorna um boolean;
  • A classe, interface ou record retornado por GetEnumerator devem conter uma propriedade pública chamada Current que deve ser do tipo contido na coleção.

Com esses atributos podemos ver na Listagem 2 como o for in funciona nos bastidores.

Listagem 2. for in nos bastidores.

var

  strItem: string;

  enum: TStringsEnumerator;

begin

   objList := TStringList.Create;

   objList.Add('Item 0');

   objList.Add('Item 1');

   objList.Add('Item 2');

      { Como usamos TStringList é retornado

     o tipo TStringsEnumerator }

   enum := objList.GetEnumerator;

   { loop da coleção }

   while enum.MoveNext do

   begin

     { Retorna o item corrente da coleção }

     strItem := enum.Current ;

     ListBox2.Items.Add(strItem)

   end;

end;

O GetEnumerator retornará o tipo TStringsEnumerator que trata itens da coleção do tipo string.

Nota: Ainda podemos ter como retorno os seguintes tipos: TListEnumerator (Pointer), TInterfaceListEnumerator (IInterface), TCollectionEnumerator (TcollectionItem), TStringsEnumerator (string) e TComponentEnumerator (TComponent).

O MoveNext navega de item a item do início ao fim da coleção. A propriedade Current recebe o item atual da coleção que foi posicionado por MoveNext. Com o for in, não precisamos nos preocupar com o trabalho nos bastidores, tirando assim algumas responsabilidades como mostra a Listagem 3.

Nota: O for in está presente em aplicações Win32 e .NET no Delphi 2005.

Listagem 3. for in lendo tipo string.

var

  strItem: string;

begin

  { em .NET utilize ListBox.Items.Clear }

  ListBox2.Clear;

  for strItem in ListBox1.Items do

    ListBox2.Items.Add(strItem);

end;

É importante frisar que o for in não serve somente para ler coleções do tipo string, mas também, outros tipos como mostra a Listagem 4.

Listagem 4. for in lendo tipo Components.

var

  objItem: TComponent;

begin

  ListBox2.Clear;

  for objItem in Form1 do

    ListBox2.Items.Add(objItem.Name + ': ' +

      objItem.ClassName);

end;

for in lendo tipo Array


const Meses: array[1..12] of string = ('Janeiro',

  'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho',

  'Julho', 'Agosto', 'Setembro', 'Outubro',

  'Novembro', 'Dezembro');

...

var

  strItem: string;

begin

  ListBox2.Clear;

  for strItem in Meses do

    ListBox2.Items.Add(strItem);

end;

As seguintes classes e seus descendentes suportam a sintaxe for in: TList, TCollection, TStrings, TInterfaceList, TComponent, TMenuItem, TCustomActionList, TFields, TListItems, TTreeNodes e TToolBar.