Lua - Iteradores
Iterator é uma construção que permite percorrer os elementos da chamada coleção ou contêiner. Em Lua, essas coleções geralmente se referem a tabelas, que são usadas para criar várias estruturas de dados, como array.
Genérico para Iterator
Um genérico para iterador fornece os pares de valores-chave de cada elemento na coleção. Um exemplo simples é fornecido abaixo.
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
Quando executarmos o código acima, obteremos a seguinte saída -
1 Lua
2 Tutorial
O exemplo acima usa a função iteradora ipairs padrão fornecida por Lua.
Em Lua, usamos funções para representar iteradores. Com base na manutenção de estado nessas funções iterativas, temos dois tipos principais -
- Iteradores sem estado
- Iteradores com estado
Iteradores sem estado
Pelo próprio nome podemos entender que este tipo de função iteradora não retém nenhum estado.
Vejamos agora um exemplo de criação de nosso próprio iterador usando uma função simples que imprime os quadrados de n números.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
Quando executarmos o programa acima, obteremos a seguinte saída.
1 1
2 4
3 9
O código acima pode ser ligeiramente modificado para imitar a maneira como a função ipairs dos iteradores funciona. É mostrado abaixo.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
function squares(iteratorMaxCount)
return square,iteratorMaxCount,0
end
for i,n in squares(3)
do
print(i,n)
end
Quando executarmos o programa acima, obteremos a seguinte saída.
1 1
2 4
3 9
Iteradores com estado
O exemplo anterior de iteração usando função não retém o estado. Cada vez que a função é chamada, ela retorna o próximo elemento da coleção com base em uma segunda variável enviada para a função. Para manter o estado do elemento atual, fechamentos são usados. O fechamento retém os valores das variáveis nas chamadas de funções. Para criar um novo fecho, criamos duas funções, incluindo o próprio fecho e uma fábrica, a função que cria o fecho.
Vamos agora ver um exemplo de criação de nosso próprio iterador no qual usaremos fechamentos.
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- The closure function is returned
return function ()
index = index + 1
if index <= count
then
-- return the current element of the iterator
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Quando executarmos o programa acima, obteremos a seguinte saída.
Lua
Tutorial
No exemplo acima, podemos ver que elementIterator tem outro método interno que usa o índice de variáveis externas locais e contagem para retornar cada um dos elementos na coleção, incrementando o índice cada vez que a função é chamada.
Podemos criar nossos próprios iteradores de função usando o fechamento conforme mostrado acima e ele pode retornar vários elementos para cada vez que iteramos na coleção.