, y así sucesivamente hasta llegar al primer elemento nil.

Un iterador es un objeto que se puede utilizar para recorrer algunos o todos los elementos de los contenedores de la biblioteca de plantillas estándar. Cada objeto iterador representa una dirección determinada dentro del contenedor.

En Lua, un iterador es una estructura que admite tipos de puntero y puede recorrer cada elemento de una colección.


Iteradores del bucle for genérico

El bucle for genérico almacena internamente la función iteradora; en realidad, guarda tres valores: la función iteradora, la constante de estado y la variable de control.

El iterador del bucle for genérico proporciona los pares clave/valor de la colección. La sintaxis es la siguiente:

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

En el código anterior, k y v son la lista de variables; pairs(t) es la lista de expresiones.

Observa el siguiente ejemplo:

Ejemplo

array = {"Google", "Ejemplo"}

for key,value in ipairs(array)
do
   print(key, value)
end

La salida del código anterior es:

1  Google
2  Ejemplo

En el ejemplo anterior hemos utilizado la función iteradora ipairs que Lua proporciona por defecto.

A continuación, veamos el proceso de ejecución del bucle for genérico:

  • Primero, la inicialización: se evalúa la expresión después de 'in'. La expresión debe devolver los tres valores que el bucle for genérico necesita: la función iteradora, la constante de estado y la variable de control. Igual que en la asignación múltiple, si la expresión devuelve menos de tres resultados, se completan automáticamente con nil; los resultados sobrantes se ignoran.
  • Segundo, se llama a la función iteradora con la constante de estado y la variable de control como argumentos (nota: para la estructura for, la constante de estado no tiene utilidad; solo se obtiene su valor durante la inicialización y se pasa a la función iteradora).
  • Tercero, los valores devueltos por la función iteradora se asignan a la lista de variables.
  • Cuarto, si el primer valor devuelto es nil, el bucle termina; de lo contrario, se ejecuta el cuerpo del bucle.
  • Quinto, se vuelve al segundo paso para llamar nuevamente a la función iteradora.

En Lua, a menudo usamos funciones para describir iteradores. Cada vez que se llama a la función, esta devuelve el siguiente elemento de la colección. Los iteradores de Lua incluyen los siguientes dos tipos:

  • Iteradores sin estado
  • Iteradores con estado múltiple

Iteradores sin estado

Un iterador sin estado es aquel que no conserva ningún estado. Por lo tanto, en un bucle podemos utilizar iteradores sin estado para evitar el costo adicional de crear cierres (clausuras).

En cada iteración, la función iteradora se llama con los valores de dos variables (la constante de estado y la variable de control) como argumentos. Un iterador sin estado solo necesita estos dos valores para obtener el siguiente elemento.

Un ejemplo típico y sencillo de este tipo de iterador sin estado es ipairs, que recorre cada elemento de un array; los índices de los elementos deben ser numéricos.

En el siguiente ejemplo, usamos una función simple para implementar un iterador que calcula el cuadrado del número n:

Ejemplo

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

La salida del ejemplo anterior es:

1    1
2    4
3    9

El estado de la iteración incluye la tabla que se recorre (la constante de estado que no cambia durante el bucle) y el índice actual (la variable de control). Tanto ipairs como la función iteradora son muy simples; en Lua podemos implementarlos así:

Ejemplo

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

Cuando Lua llama a ipairs(a) para comenzar el bucle, obtiene tres valores: la función iteradora iter, la constante de estado a y el valor inicial de la variable de control 0. Luego Lua llama a iter(a,0), que devuelve 1, a


Iteradores con estado múltiple

En muchos casos, el iterador necesita almacenar múltiples informaciones de estado en lugar de una simple constante de estado y una variable de control. El método más sencillo es usar cierres (clausuras). Otra forma es encapsular toda la información de estado dentro de una tabla y usar esa tabla como la constante de estado del iterador. Dado que en este caso toda la información se puede almacenar en la tabla, la función iteradora generalmente no necesita un segundo argumento.

En el siguiente ejemplo, creamos nuestro propio iterador:

Ejemplo

array = {"Google", "Ejemplo"}

function elementIterator (collection)
   local index = 0
   local count = #collection
   -- Función de cierre (clausura)
   return function ()
      index = index + 1
      if index <= count
      then
         -- Devuelve el elemento actual del iterador
         return collection[index]
      end
   end
end

for element in elementIterator(array)
do
   print(element)
end

La salida del ejemplo anterior es:

Google
Ejemplo

En el ejemplo anterior podemos ver que elementIterator utiliza una función de cierre (clausura) para calcular el tamaño de la colección y mostrar cada elemento.

Otras extensiones