Bienvenidos sean a este post, hoy comenzaremos a hablar sobre el entorno en Lua donde si bien hemos hablado sobre las variables locales hoy nos centraremos en los otros tipos de variables.

Anuncios

En el caso de las globales hasta ahora hemos visto que alcanza con solamente asignarlos para acceder y modifcarlas, sin embargo en algunas circunstancias necesitaremos alguna forma de meta-programacion, tal como cuando necesitamos manipular una variable global cuyo nombre esta almacenado en otra variable o algo computado en la ejecucion, para conseguir el valor de esta variable muchos se sienten tentados de usar algo como esto:

valor = loadstring("return " .. nombrevar)()

Si nombrevar tiene un valor x, la concatenacion devolvera «return x» lo cual cuando corre logra el resultado deseado, sin embargo este codigo envuelve la creacion y compilacion de un nuevo chunk, se puede realizar el mismo efecto con el codigo siguiente, el cual es mas que una orden de magnitud mas eficiente que el previo:

valor = _G[nombrevar]

Porque el entorno es una tabla regular, simplemente puedes indexarlo con la clave deseada (el nombre de la variable), en una forma similar puedes asignar un valor a variable global cuyo nombre es computado dinamicamente escribiendo _G[nombrevar] = valor pero cuidado porque algunos programadores se sienten un poco excitados con estas facilidades y terminan escribiendo un codigo como el siguiente:

Anuncios
_G["a"] = _G["var1"]

Lo cual es solo una forma mas complicada de escribir a = var1, una generalizacion del problema previo es permitir campos en el nombre dinamico tal como «io.read» o «a.b.c.d» y si escribimos _G[«io.read»] no conseguiremos el campo read de la tabla io pero podemos escribir una funcion getfield como getfield(«io.read») la cual devolvera el resultado esperado, esta funcion es principalmente un bucle el cual comienza con _G y pasa campo por campo:

function getfield(f)
	local v = _G
	for p in string.gmatch(f, "[%w_]+") do
		v = v[p]
	end
	return v
end

Confiamos en gmatch de la libreria string para iterar sobre todas las palabras en f, donde «palabra» es una secuencia de una o mas caracteres alfanumericas y guiones bajos, la funcion correspondiente para setear campos es un poco mas compleja porque un asignamiento como a.b.c.d = v es equivalente al siguiente codigo:

local temp = a.b.c
temp.d = v
Anuncios

Es correcto debemos recuperar al ultimo nombre y luego lo maneja separadamente, la siguiente funcion setfield hace la tarea y tambien crea tablas intermedias en un camino cuando no existan:

function setfield(f, v)
	local t = _G
	for p, d in string.gmatch(f, "([%w_]+)(.?)") do
		if d == "." then
			t[p] = t[p] or {}
			t = t[p]
		else
			t[p] = v
		end
	end
end

Esta funcion comienza con la tabla de globales, luego en el bucle chequea si d no es la ultima palabra en donde creara una tabla en caso de estar ausente, luego consigue la tabla, en caso contrario de ser la ultima palabra hace el asignamiento, en el bucle for podes ver el nuevo patron que captura el nombre del campo en p y un opcional seguido de un punto llamado d, si un campo no es seguido por un punto es considerado como el ultimo nombre y hace lo que dijimos antes, veamos el siguiente ejemplo:

setfield("t.x.y", 10)

Creamos una tabla global t, otra tabla t.x y asignamos 10 a t.x.y, si buscamos el valor:

> print(t.x.y)
10
> print(getfield("t.x.y"))
10
>
Anuncios

En resumen, hoy hemos visto como son las variables globales, como trabajan, como se usan habitualmente, como se pueden adaptar a otros requerimientos, tambien hemos visto nombres dinamicos, para que se usan y cual es su mejor utilidad, 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.50

Anuncio publicitario