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.
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.
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.
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.
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.