Bienvenidos sean a este post, hoy hablaremos sobre un tema mas complejo porque en determinadas circunstancias un iterador necesita mas estados que encajen mas que en un estado invariable y una variable de control, para ello la solucion mas simple es usar cierres, otra solucion alternativa es empaca todo lo necesario dentro de una tabla y usar esta tabla como el estado invariable para la iteracion, de esta forma un iterador puede mantener mucha mas data a media que necesita durante el bucle, y a su vez puede cambiar esta informacion a medida que avanza.

Anuncios

A pesar de que el estado es siempre la misma tabla (y de esta forma invariable), los contenidos de la tabla cambian a lo largo del bucle porque dichos iteradores tienen toda su informacion en el estado, ocasionando que habitualmente ignoren el segundo argumento provisto por el for generico (la variable iteradora).

Como ejemplo de esta tecnica reescribiremos al iterador palabrasTodas, el cual atraviesa todas las palabras de la linea de entrada pero esta vez mantendremos su estado usando dos campos: linea y pos, la funcion que comienza al iterador es simple, solo debe devolver la funcion del iterador y el estado inicial:

local iterador
function palabrasTodas()
	local estado = { linea = io.read(), pos = 1}
	return iterador, estado
end

En este caso la funcion iterador es la que hace la verdadera magia, ahora agreguemos la funcion:

function iterador(estado)
	while estado.linea do
		local i,f = string.find(estado.linea, "%w+", estado.pos)
		if i then
			estado.pos = f + 1
			return string.sub(estado.linea, i, f)
		else
			estado.linea = io.read()
			estado.pos=1
		end
	end
	return nil
end
Anuncios

En esta funcion recibiremos a estado, luego usaremos un while donde mientras estado.linea sea verdadero luego usaremos dos variables para almacenar la posicion inicial y final de cada palabra (estas son i y f respectivamente), el modificador “%w+” se encarga de buscar palabras y estado.pos es el valor inicial para comenzar la busqueda, luego usaremos un condicional donde chequea si i tiene un valor, en caso de ser cierto procede a asignar el valor de f mas 1 a estado.pos, por ultimo devolveremos el extracto de estado.linea por medio de string.sub a traves de los valores que tenemos en i y f, en caso contrario procedemos a usar io.read para ingresar un nuevo valor a estado.linea y volvemos a decir que estado.pos es igual a 1, por ultimo retornaremos un nil cuando se haya completado el bucle.

Nota: En el caso que incrementamos a f en uno y lo asignamos a estado.pos es para que pase a una siguiente palabra.

Siempre que sea posible deberias intentar usar iteradores sin estado, aquellos que mantiene todos sus estados en las variables del for, con ellos no es necesario crear nuevos objetos cuando inicia el bucle pero si no puedes encajar tu iteracion en este modelo entonces deberias intentar con cierres, ademas de ser mas elegante, habitualmente un cierre es mas eficiente que usar un iterador con una tabla, algunas ventajas son:

  1. Es mas facil crear un cierre que una tabla
  2. Acceder a variable locales es mas rapido que campos de una tabla

Aunque este es una opcion interesante para implementar mas adelante veremos una opcion de iteradores con corutinas pero trayendo mas complejidad.

Anuncios

En resumen, hoy hemos visto un iterador mas complejo, como puede ser una alternativa para los iteradores sin estados, hemos visto unos ejemplos practicos, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00