Ir al contenido principal

Tipos de datos

Lua es un lenguaje de tipos dinámicos. Al igual que en otros lenguajes dinámicos, el tipo de una variable es inferido en función del valor asignado. En esta afirmación hay que tener en cuenta dos conceptos:

  • Declaración
  • Asignación

Cuando hablamos de lenguajes de tipos estáticos, como por ejemplo C, C++, C#, Java entre otros, realizamos las dos operaciones. Primero declaramos la variable, que tiene que ser obligatoriamente de un tipo y luego le asignamos un valor, que debe ser concordante con el tipo declarado.

En Lua y en otros lenguajes dinámicos, se hacen las dos operaciones durante la asignación. Esto quiere decir que cuando hacemos una asignación a = "Valor", estamos declarando una variable a, a la cual le asignamos el valor "Valor". A partir del valor asignado, el intérprete de Lua es capaz de 'adivinar' el tipo. En el caso de nuestro ejemplo, "Valor" es un literal de cadena y entonces la variable a será del tipo string. Dicho esto, si intentamos declarar una variable en Lua sin asignarle un valor, el intérprete nos dará un error.


Tipos básicos de Lua

En Lua se definen ocho tipos básicos:

nil Representa un valor nulo o inválido
boolean Representa un valor booleano: verdadero, falso
number Representa un número real en coma flotante de doble precisión
string Representa una cadena de caracteres
function Referencia a una función declarada
userdata Representa cualquier otro tipo de datos almacenados en la variable
thread Referencia un hilo para entornos multi-hilo
table Referencia a un array asociativo multidimensional

Podemos conocer el tipo de una variable en todo momento usando la función type():

print(type(11.6))                --> number
print(type("Hola Mundo"))        --> string
print(type(print))               --> function
print(type(false))               --> boolean
print(type(nil))                 --> string
print(type({a = 1}))             --> table

nil

El tipo nil indica que no hay valor definido. Si el valor es retornado para una variable, quiere decir que la variable no está definida. Si este valor es retornado por una función significa que no hay valor a devolver. Por ejemplo:

> print(a)
nil

En el ejemplo anterior se intenta imprimir el valor de una variable a, pero el valor devuelto es nil. En este caso significa que la variable no ha sido declarada y por lo tanto no tiene valor. Recuerda que toda variable que se le asigne el valor nil desaparece, porque para que exista, debe tener un valor asignado diferente de nil.

Cuando se asigna nil a un elemento de una tabla, al igual que en las variables, este elemento es anulado y por consiguiente, eliminado. Si se asigna nil a una variable que tiene una referencia a una tabla, la tabla entera será anulada y eliminada. Escribe el siguiente código en un archivo y ejecútalo con Lua para ver un ejemplo que te permita comprender mejor este concepto:

tabla1 = { elm1 = "val 1", elm2 = "val 2", elm3 = "val 3" }

for k, v in pairs(tabla1) do
    print(k .. " _ " .. v)
end

tabla1.elm2 = nil

for k, v in pairs(tabla1) do
    print(k .. " _ " .. v)
end

El resultado es el siguiente:

elm3 _ val 3
elm2 _ val 2
elm1 _ val 1
elm3 _ val 3
elm1 _ val 1

Podemos ver que las tres primeras lineas corresponden a los tres elementos de la tabla. Pero en las dos últimas, falta el elemento elm2 que hemos eliminado asignándole nil.


boolean

Los tipos boolean representan dos posibles valores: true o false. Puedes probar el siguiente código para entender mejor el concepto:

a = true
b = false

function PrintValue(value)
    if value then
        print("Verdadero")
    else
        print("Falso")
    end
end

PrintValue(a) --> a = true
PrintValue(b) --> b = false

El ejemplo produce la siguiente salida:

Verdadero
Falso

number

En Lua existe un solo tipo numérico con el que se pueden representar varios formatos numéricos, por ejemplo:

  • 5
  • 5.1
  • 0.6
  • 3e+2
  • 0.4e-1
  • 3.423946103e+06

string

Este tipo representa una cadena de caracteres. Esta cadena se puede delimitar usando comillas dobles (") o comillas simples (') indistintamente. Así por ejemplo son expresiones de cadenas válidas:

cadena1 = "Cadena con comillas dobles"
cadena2 = 'Cadena con comillas simples'

Cuando queremos asignar una cadena que contiene múltiples lineas, podemos usar dobles corchetes "[[]]" para englobar toda la cadena:

text = [[ Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
Vivamus ornare viverra augue, nec auctor sem pellentesque ac. 
Nulla at varius quam. 
Ut velit augue, ornare a sapien et, ultricies egestas mauris.
Nam augue nibh, vulputate ut sagittis eu, vulputate imperdiet dolor.  ]]

Si realizamos una operación matemática entre un tipo numérico y un tipo string, el intérprete de Lua intentará convertir la cadena de texto en un valor numérico y realizar la operación después. Si la cadena no puede ser convertida a un número el intérprete dará un error:

> print(8 + "2")
10
> print("8" + "2")
10
> print("8 + 2")
8 + 2
> print("3e2" * "3")
900
> print("numero" + 5)
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
stdin:1: in main chunk
[C]: in ?

Dos o más cadenas de texto se pueden concatenar usando dos puntos consecutivos (..) entre las cadenas o variables:

> a = "Conca"
> b = "tenación"
> print(a .. b)
Concatenación
> print("Conca" .. "tenación")
Concatenación

Se puede obtener la longitud de una cadena usando el operador almohadilla (#):

> cadena = "Longitud"
> longitud = #cadena
> print(longitud)
8
> print(#cadena)
8
> print(#"Longitud")
8

table

El tipo table corresponde a un array asociativo, esto significa, que podemos usar números y cadenas para indizar los elementos. Del mismo modo, el array puede ser multinivel. Podemos inicializar una tabla vacía o añadiendo elementos:

tabla1 = {}

tabla2 = { "naranja", "manzana", "piña", "plátano" }

En una tabla, los índices no tienen que ser necesariamente del mismo tipo, pudiendo existir índices de tipo cadena y de tipo numérico:

tbl = {}
tbl["indice"] = "valor"

i = 5
tbl[i] = 10
tbl[i] = tbl[i] + 5

for k, v in pairs(tbl) do
    print(k .. " : " .. v)
end

Si ejecutamos el código anterior obtenemos el siguiente resultado:

$ lua TestTableIndices.lua
indice : valor
5 : 15

Las tablas en Lua son de índice 1, esto significa que por defecto, el primer elemento de una tabla cuando no se especifiquen índices explícitamente será 1. Esto marca una diferencia con multitud de lenguajes cuyos arrays son de índice 0. Veamos un ejemplo:

tabla = { "naranja", "manzana", "pera", "uva" }

for k, v in pairs(tabla) do
    print("Índice: " .. k .. ", Valor: " .. v)
end

Cuyo resultado es:

$ lua TestTableIndices2.lua
Indice: 1, Valor: naranja
Indice: 2, Valor: manzana
Indice: 3, Valor: pera
Indice: 4, Valor: uva

Las tablas en Lua son dinámicas por lo que no tienen un tamaño definido. Una tabla irá ajustando su tamaño en función del número de elementos que contenga automáticamente. Eso quiere decir, que es el intérprete de Lua quien se ocupa de gestionar la memoria necesaria para almacenar los elementos de la tabla.


function

El tipo function almacena una referencia a una función. Esto significa que podemos asignar una función a una variable para usarla después:

function factorial(n)
    if n == 0 then
        return 1
    else
        return n * factorial(n - 1)
    end
end

print(factorial(4))
factorialVar = factorial
print(factorialVar(4))

Al ejecutar el código anterior obtenemos el siguiente resultado:

$ lua TestTipoFunction.lua
24
24

El tipo function también acepta las funciones anónimas pasadas como parámetros:

function Anonima(tbl, fun)
    for k, v in pairs(tbl) do
        print(fun(k, v))
    end
end

tabla = { clave1 = "valor1", clave2 = "valor2" }

Anonima(tabla, function(clave, valor)
    return clave .. " = " .. valor\nend)

El resultado del código anterior es el siguiente:

$ lua TestFunctionAnonima.lua
clave2 = valor2
clave1 = valor1

thread

Las variables de tipo thread contienen referencias a hilos gestionados por el sistema operativo. Estos hilos permiten la realización de tareas en paralelo pero, pueden ser bastante difíciles de manejar. Como alternativa a los hilos, Lua maneja las llamadas corutinas, que permiten cierto paralelismo usando un solo hilo. Las corutinas son gestionadas directamente por el intérprete de Lua.


userdata

Las variables de tipo userdata contienen referencias a datos arbitrarios de C de cualquier tipo. En este tipo de datos se suelen almacenar referencias a estructuras y punteros.