English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Iteradores do Lua

Iterador (iterator) é um objeto que pode ser usado para percorrer parte ou todos os elementos de um contêiner da biblioteca de templates padrão, cada objeto de iterador representa um endereço determinado no contêiner.

No Lua, o iterador é uma estrutura de tipo de ponteiro que pode percorrer cada elemento da coleção.

Iterador genérico for

O iterador genérico for salva a função de iteração interna, na verdade ele salva três valores: função de iteração, constante de estado, variável de controle.

O iterador genérico for fornece a chave da coleção/Correta de valor, o formato de sintaxe é o seguinte:

for k, v in pairs(t) do
    print(k, v)
end

Nos códigos acima, k, v são listas de variáveis; pairs(t) é uma lista de expressões.

Verifique o seguinte exemplo:

array = {"Google", "w3codebox"}
for key, value in ipairs(array) 
do
   print(key, value)
end

O resultado da execução do código acima é:

1  Google
2  w3codebox

No exemplo acima, usamos a função de iteração padrão fornecida pelo Lua, ipairs.

A seguir, vamos ver o processo de execução do for genérico:

  • Primeiro, inicialize, calcule o valor da expressão após o in, a expressão deve retornar três valores necessários para o for genérico: função de iteração, constante de estado, variável de controle; como na atribuição de múltiplos valores, se o número de resultados da expressão for insuficiente para três, será automaticamente complementado com nil, e a parte em excesso será ignorada.

  • Segundo, chame a função de iteração com os parâmetros de constante de estado e variável de controle (atenção: para a estrutura for, a constante de estado não é útil, pois apenas obtém seu valor e passa para a função de iteração no início).

  • Terceiro, atribua o valor retornado pela função de iteração a uma lista de variáveis.

  • Quarto, se o primeiro valor retornado for nil, o loop termina, caso contrário, execute o corpo do loop.

  • Quinto, volte ao passo dois e chame a função de iteração novamente

Em Lua, usamos frequentemente funções para descrever iteradores, onde cada chamada da função retorna o próximo elemento do conjunto. Os iteradores do Lua incluem os seguintes dois tipos:

  • Iterador sem estado

  • Iterador de múltiplos estados

Iterador sem estado

Um iterador sem estado é aquele que não mantém nenhum estado, portanto, podemos usar iteradores sem estado no loop para evitar criar closures e custos adicionais.

Em cada iteração, a função de iteração é chamada com os valores dos dois vetores (constantes de estado e variável de controle), um iterador sem estado utiliza esses dois valores para obter o próximo elemento.

Um exemplo típico e simples de iterador sem estado é ipairs, que percorre cada elemento do array.

A seguir, usaremos uma função simples para implementar o iterador, calculando o quadrado do número n:

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

O resultado da saída do exemplo acima é:

1    1
2    4
3    9

O estado de iteração inclui a tabela percorrida (um estado constante que não muda durante o processo de iteração) e o índice atual (um variável de controle), os funções ipairs e de iteração são muito simples, podemos implementá-las assim no Lua:

function iter(a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end
 
function ipairs(a)
    return iter, a, 0
end

Quando o Lua chama ipairs(a) para começar o loop, ele obtém três valores: a função de iteração iter, a constante de estado a e o valor inicial do variável de controle 0; então o Lua chama iter(a,0) para retornar 1, a[1](a menos que a[1=nil);A segunda chamada de iteração para iter(a,1) retorna 2, a[2...... até o primeiro elemento nil.

Iterador de múltiplos estados

Muitas vezes, os iteradores precisam armazenar várias informações de estado, não apenas constantes de estado simples e variáveis de controle. O método mais simples é usar closure, e há outro método que envolve encapsular todas as informações de estado em uma tabela, usando a tabela como constante de estado do iterador. Neste caso, todas as informações podem ser armazenadas dentro da tabela, então a função de iteração geralmente não precisa de um segundo parâmetro.

Nos exemplos abaixo, criamos nosso próprio iterador:

array = {"Google", "w3codebox"}
function elementIterator(collection)
   local index = 0
   local count = #collection
   -- Função closure
   return function ()
      index = index + 1
      if index <= count
      then
         --  Retorna o elemento atual do iterador
         return collection[index]
      end
   end
end
for element in elementIterator(array)
do
   print(element)
end

O resultado da saída do exemplo acima é:

Google
w3codebox

Nos exemplos acima, podemos ver que o elementIterator usou a função closure para calcular o tamanho da coleção e imprimir cada elemento.