Bienvenidos sean a este post, como vimos anteriormente en algunas funciones Lua puede usar un numero variable de argumentos, si bien usamos a print para ver un caso y este esta escrito en C nosotros podemos definir en Lua otro con las mismas condiciones, veamos el siguiente ejemplo:

Anuncios
tinchicus@dbn001dsk:~/lenguaje/lua$ lua5.3
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> function agregar(...)
>> local s = 0
>> for i,v in ipairs{...} do
>> s = s + v
>> end
>> return s
>> end
> print(agregar(3, 4, 10, 25, 12))
54
>

La primera curiosidad que vemos son los tres puntos (…), esto lo indica a Lua que el argumento a recibir es variable y cuando esta funcion es llamada estos son recolectados internamente, estos argumentos recolectados son llamados varargs (argumentos variables) de la funcion, para poder acceder a estos “varargs” debemos usar nuevamente los tres puntos pero ahora como expresion, esto se observa en el momento de usar el for con ipairs, observen como se uso entre llaves para que equivalga a un array, o una tabla, con esto el for pasara todos los valores del “array” a la variable s sumandole el valor nuevo al existente, s = s + v, una vez terminado nos devolvera el valor en s, por ultimo salimos de la funcion y observen como al usar un print con la funcion agregar y los valores informados, nos devolvio la suma de todos ellos, si quieren pueden probar variando la cantidad de datos en agregar para ver los distintos resultados.

La expresion … se comporta como una multiple funcion de devolucion porque nos devuelve todos los varargs de funcion actual, por ejemplo:

local a, b = ...

Esto completara los dos valores con los primeros dos argumentos informados, en caso de faltar alguno el mismo sera reemplazado con nil, tal como vimos hasta ahora, veamos una equivalencia de trabajar de esta forma, tomemos la siguiente funcion:

function foo(a, b, c)

Equivaldria a:

function foo(...)
local a, b, c = ...
Anuncios

Para aquellos que les gusta trabajar con la forma de pasar argumentos en Perl se sentiran mas comodos con la segunda opcion, veamos la siguiente funcion:

function foo(...) return ... end

Esta funcion solamente retorna todos los argumentos informados al momento de llamar la funcion, veamos el siguiente ejemplo:

function foo1(...)
	print("Llamando a foo: " ...)
	return foo(...)
end

En este caso tendriamos una funcion llamada foo1 la cual mostrara un mensaje de “llamando a foo y luego mostrara todos los valores del argumento de foo1, para luego devolver a foo con los mismos argumentos, esto se llama funcion de identidad de multiples valores, usualmente se lo usa para rastrear llamadas a una funcion especifica, veamos otro ejemplo util, Lua provee funciones separadas para formatear texto (string.format) y otra para escribir texto (io.write) y nosotros podriamos combinarlos a ambos como se ve en el siguiente ejemplo:

function fwrite(fmt, ...)
	return io.write(string.format(fmt, ...))
end

En este caso utilizamos una variable y luego a varargs, con esto podra interpretar que el primer argumento corresponde a fmt y todos los restantes (en caso de existir) corresponderan a varargs.

Nota: En el caso de existir mas parametros a varargs, estos seran asignados como los primeros parametros y una vez completado los argumentos extras seran asignados a varargs.
Anuncios

Para entender mejor el concepto veamos unos ejemplos aplicando valores a la funcion anterior:

fwrite()		<==>	fmt=nil, varargs=nil
fwrite("a")		<==>	fmt="a", varargs=nil
fwrite("%d%d",4,5,6)	<==>	fmt="%d%d", varargs=4, 5, 6

A la izquierda podemos ver las llamadas con los distintos valores y la derecha los parametros finales, en el primer caso al no firmar nada vemos que todo es nil, en el segundo caso fmt va a ser igual a “a”, varargs es igual a nil, en el tercer caso el primer valor va a fmt y los restantes se almacen en varargs, para poder interactuar con los valores de varargs debemos asignarlos a una tabla, como vimos anteriormente en la funcion agregar.

En contadas ocasiones podemos contener valores nil validos (¿?), y para ello podemos usar la funcion select, la llamada a select siempre tiene un argumento fijo llamada selector y adicionalmente un numero variable de argumentos extras, si el selector es un numero n, select devuelve el argumento extra n veces, de otra manera, el selector deberia ser la cadena “#” asi de esta forma select devuelve el total de argumentos extras, veamoslo a traves del siguiente ejemplo:

for i=1, select('#',...) do
	local arg = select(i, ...)
	<bloque del loop>
end
Anuncios

En este caso tenemos un bucle for donde el valor inicial de i es 1, luego por medio de select usa a numeral (#) para devolver el total de entradas, esto incluira los nils que puede haber en el mismo, y luego usaremos a varargs, para luego crear un variable local llamada arg donde usaremos nuevamente a select en el cual cambiaremos la posicion por medio de i y luego los valores de varargs, para despues proseguir con el bloque del loop.

Existe un mecanismo viejo para utilizar varargs, si bien este es igual a lo visto anteriormente porque utiliza los tres puntos como ultimo parametro, este no poseia la posibilidad de usar a los tres puntos como expresion, en su lugar la funcion varargs posee una variable local oculta llamada arg, la cual recibia la tabla creada con varargs, y esta a su vez posee un campo donde se almacena el numero total de argumentos extras, veamos el siguiente ejemplo:

function foo(a, b, ...)
	local arg = {...}; arg.n=select("#", ...)
	< bloque de la funcion >
end

En este caso observen como creamos una tabla llamada arg, luego le asignaremos el total al campo n de la tabla, como podran observar cada vez que llamamos a esta funcion se creara una nueva tabla, en cambio con el nuevo mecanismo solo se creara la tabla cuando sea necesario.

Anuncios

En resumen, hoy hemos visto numero variable de argumentos en una funcion, hemos visto como es su argumento, como utilizarlo, las distintas conductas en una funcion, en un bucle, tambien como asignarlo a una lista de variables, y el mecanismo viejo y nuevo de estos argumentos, 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