Jump to content

Funções iteradoras em Lua


Lordfire

Recommended Posts

Iteradores são funções especiais criadas para iterar, ou seja, percorrer, listas, vetores (arrays), matrizes, tabelas ou o que quisermos. Nós criamos iteradores para usar na função for. Um exemplo de iterador que você já deve conhecer é o pairs. Vamos supor que eu tenha a seguinte tabela:

 

k = {1, 2, 3, 4, 5}
E eu queira iterar por todos eles imprimindo o seu quadrado. Como faríamos isso? Casualmente, o código seria este:

 

for i = 1, 5 do
	print(i ^ 2)
end
Mas e se eu quiser fazer isso várias vezes? Com uma lista que não segue um padrão? Então criamos um iterador, mas primeiro, vamos entender a estrutura de um em pseudocódigo Lua:

 

function iterator(values)
	local pos = 0 --posição do iterador na lista
	return function()
		pos = pos + 1
		if values[pos] ~= nil then
			return values[pos]
		end
		return nil
	end
end
Perceba que eu não retorno um valor especifico ao chamar a função iterator(), eu retorno uma nova função. Essa função será chamada pelo for até que seu retorno seja nil, onde Lua assume que o iterador acabou. E como eu sei quando acaba? Simples, há uma variável (chamei, neste caso, de pos) que armazena a posição dentro do array values do próximo valor a ser retornado. A cada iteração, o valor aumenta em 1 dentro da função. Quando eu acessar um índice dentro do array que não existe, seu valor (values[pos]) será nil, portanto eu testo essa condição.

 

Parece bastante complexo, mas vamos voltar ao exemplo do quadrado. Chamarei minha função iteradora de square:

 

function square(numbers)
	local pos = 0
	return function()
		pos = pos + 1
		if values[pos] ~= nil then
			return values[pos] ^ 2
		end
		return nil
	end
end
A cada chamada da função de retorno, eu aumento a posição e retorno este elemento elevado ao quadrado. Então, usarei a função assim:

 

for i in square(k) do
	print(i)
end
Que funciona como o esperado:

 

O que mais podemos fazer com iteradores? Podemos, por exemplo, bloquear uma palavra usando a função onTalk do xotservx:

 

local palavra = "jujuba"

function splitWords(phrase)
	local pos = 0, words = phrase:gmatch("%w+")
	return function()
		pos = pos + 1
		if words[pos] ~= nil then
			return words[pos]
		end
		return nil
	end
end

function onTalk(cid, type, text, position)
	for w in splitWords(text) do
		if w = palavra then
			return false
		end
	end
	return true
end
Claro que esse exemplo é bastante simplório, mas demonstra a utilidade dos iteradores. Neste caso, eu testo todas as palavras que o player falou para encontrar uma palavra especifica que eu defini. Podemos transformar isso tudo em um loop while, para você entender um pouco melhor:

 

local words = splitWords(text)
	while w = words() do
		if w == nil then
			break
		end
		if w = palavra then
			return false
		end
	end
end
return true
Usando o iterador, ganhamos organização no código e o controle do for. Espero que façam bom uso de iteradores para organizar seus códigos :) Edited by Lordfire
Link to comment
Share on other sites

otima explicaçao LF '--' eu realmente achu q todo mundo q quer aprender lua deveria ler o manual lua todo kk' mas sua explicaçao realmente ficou muito boa, e esses interadores podem ser realmente uteis em alguns casos... ;p

Link to comment
Share on other sites

Ótimo tutorial!

((Na verdade, deu uma ideia de script para criar, mas não acho que eu tenha conhecimento suficiente por enquanto... ._.'

Quem sabe depois que eu estudar mais hahaha ))

+rep

Link to comment
Share on other sites

Ótimo tutorial!

 

((Na verdade, deu uma ideia de script para criar, mas não acho que eu tenha conhecimento suficiente por enquanto... ._.'

 

Quem sabe depois que eu estudar mais hahaha ))

 

+rep

Joga na roda que a gente faz e explica :)
Link to comment
Share on other sites

  • 1 month later...

Apenas complementando, a funcao que vai ser usada dentro da iteracao pode tambem receber parametros, e ele deve ser colocado no return, apos o nome da funcao. Ex.:

function pairs(tab)
	local function void(_table, last_index)
		local index = next(_table, last_index)
		if not index then
			return nil
		else
			return index, _table[index]
		end
	end

	return void, tab, nil
end

Note que no return da funcao pairs, eu retorno primeiro o nome da funcao, e em seguida seus parametros, o nil e meramente ilustrativo pois o last_index nesse caso inicia nulo

A estrutura de funcoes iteradoras e assim:

function iterator(...)
   return function(...)                  
      if exp then -- condicao de repeticao
         return ... -- valores retornados a cada iteracao
      else                   
         return nil -- retorno nulo para parar a iteracao            
      end           
   end, ...
end
Link to comment
Share on other sites

×
×
  • Create New...