Programación · Lenguajes de programación
Tutorial de Lua para principiantes
Respuesta corta
Lua es un lenguaje de scripting ligero e incrustable que se usa en videojuegos, Roblox (mediante su dialecto Luau), Neovim, Redis y dispositivos embebidos. Tiene una sintaxis reducida y una única estructura de datos, la tabla, que sirve como arreglo, diccionario y objeto. Esta página cubre la instalación de Lua, las variables y los tipos, el control de flujo, las funciones, las tablas, las metatablas, el manejo de errores con pcall y un ejemplo completo.
Qué es Lua y para qué se usa
Lua es un lenguaje de scripting pequeño, rápido y de tipado dinámico creado en 1993 en la PUC-Rio, una universidad de Brasil. Todo su intérprete es una biblioteca compacta escrita en C, lo que facilita incrustarlo en programas más grandes. Tiene una sola estructura de datos, la tabla, y muy pocos conceptos, por lo que se aprende rápido.
Lua se usa sobre todo como lenguaje de scripting incrustado: motores de videojuegos y videojuegos (Roblox usa un dialecto de Lua llamado Luau; LÖVE y Defold usan Lua), el editor Neovim, la base de datos Redis, herramientas de red como Nginx con OpenResty y muchos dispositivos embebidos. LuaJIT es un popular compilador just-in-time para código Lua 5.1.
Instala Lua y ejecuta Hola, mundo
Instala Lua con tu gestor de paquetes (por ejemplo brew install lua o apt install lua5.4) o compílalo desde el código fuente en lua.org. Ejecuta lua sin argumentos para abrir un prompt interactivo.
-- hello.lua
print("Hello, world!")lua hello.lua
# Hello, world!Los comentarios empiezan con --. Un comentario de bloque se escribe --[[ ... ]]. Las instrucciones no necesitan punto y coma.
Variables y tipos básicos
Las variables son globales por defecto. Declara siempre las variables con local, a menos que de verdad quieras una global. Lua tiene ocho tipos básicos; los que usas a diario están a continuación.
local name = "Lua"
local year = 1993 -- integer
local pi = 3.14159 -- float
local ok = true
local nothing = nil
print(type(name), type(year), type(nothing)) -- string number nil
print(math.type(year), math.type(pi)) -- integer float
print(name .. " " .. year) -- Lua 1993 (.. joins strings)
print(#name) -- 3 (length)
print(7 / 2, 7 // 2, 7 % 2, 2 ^ 10) -- 3.5 3 1 1024.0
print(string.format("%.2f", pi)) -- 3.14
print(tonumber("42") + 1, tostring(10)) -- 43 10| Tipo | Ejemplo | Notas |
|---|---|---|
| nil | nil | ausencia de valor; las variables sin asignar son nil |
| boolean | true, false | solo false y nil son falsos; 0 y "" son verdaderos |
| number | 42, 3.14 | subtipos entero y flotante desde Lua 5.3 |
| string | "hi", 'hi', [[long]] | cadenas de bytes inmutables |
| table | {1, 2, x = 3} | la única estructura de datos |
| function | function() end | valores de primera clase |
El operador de desigualdad es ~=, no !=. Los operadores lógicos son las palabras and, or y not.
Control de flujo
Los bloques terminan con la palabra clave end. Lua tiene if/elseif/else, while, repeat ... until, un for numérico y un for genérico que funciona con iteradores.
local score = 72
if score >= 90 then
print("A")
elseif score >= 70 then
print("B") -- B
else
print("C")
end
for i = 1, 3 do -- 1 to 3, inclusive
io.write(i, " ") -- 1 2 3
end
print()
for i = 10, 1, -4 do io.write(i, " ") end -- 10 6 2
print()
local n = 3
while n > 0 do n = n - 1 end
repeat
n = n + 1
until n >= 2
print(n) -- 2No existe la instrucción continue; usa goto continue con una etiqueta ::continue::, o reestructura el bucle con un if.
Funciones
Las funciones son valores. Pueden recibir un número variable de argumentos con ... y devolver varios valores. Las clausuras capturan variables locales del ámbito que las contiene.
local function add(a, b)
return a + b
end
local function minmax(t)
local lo, hi = math.huge, -math.huge
for _, v in ipairs(t) do
lo, hi = math.min(lo, v), math.max(hi, v)
end
return lo, hi -- two return values
end
local function counter()
local count = 0
return function() -- a closure
count = count + 1
return count
end
end
print(add(2, 3)) -- 5
local lo, hi = minmax({4, 9, 1})
print(lo, hi) -- 1 9
local next_id = counter()
print(next_id(), next_id()) -- 1 2
local function sum(...)
local total = 0
for _, v in ipairs({...}) do total = total + v end
return total
end
print(sum(1, 2, 3)) -- 6Tablas: arreglos, diccionarios y objetos
Una tabla es un arreglo asociativo que puede indexarse con cualquier valor excepto nil. La misma estructura sirve como arreglo, diccionario, conjunto, módulo u objeto. Por convención, los arreglos empiezan en el índice 1.
local fruits = {"apple", "banana"}
table.insert(fruits, "cherry")
print(#fruits, fruits[1]) -- 3 apple
for i, f in ipairs(fruits) do -- array part, in order
print(i, f)
end
local ages = {ann = 31, bo = 25}
ages["cy"] = 40
ages.bo = nil -- remove a key
for k, v in pairs(ages) do -- all keys, order not defined
print(k, v)
end
table.sort(fruits, function(a, b) return a > b end)
print(table.concat(fruits, ", ")) -- cherry, banana, appleMetatablas y Lua orientado a objetos
Las metatablas son la característica distintiva de Lua. Una metatabla asociada a una tabla cambia su comportamiento: __index proporciona las claves que faltan (se usa para la herencia) y campos como __add, __eq y __tostring sobrecargan operadores. La sintaxis con dos puntos obj:method() pasa el objeto como primer parámetro oculto self.
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({x = x, y = y}, Vector)
end
function Vector:length()
return math.sqrt(self.x ^ 2 + self.y ^ 2)
end
Vector.__add = function(a, b) return Vector.new(a.x + b.x, a.y + b.y) end
Vector.__tostring = function(v) return "(" .. v.x .. ", " .. v.y .. ")" end
local v = Vector.new(3, 4) + Vector.new(0, 0)
print(tostring(v)) -- (3, 4)
print(v:length()) -- 5.0Lua también tiene corrutinas (coroutine.create, coroutine.resume, coroutine.yield), que permiten que una función se pause y se reanude más tarde. Los scripts de videojuegos las usan a menudo para comportamientos paso a paso que abarcan varios fotogramas.
Manejo de errores
Lanza un error con error(message). Captúralo con pcall (llamada protegida), que devuelve false más el error en lugar de detener el programa. Muchas funciones de la biblioteca devuelven nil y un mensaje de error en lugar de lanzar un error, como hace io.open.
local function divide(a, b)
if b == 0 then
error("division by zero")
end
return a / b
end
local ok, result = pcall(divide, 10, 2)
print(ok, result) -- true 5.0
ok, result = pcall(divide, 1, 0)
print(ok, result) -- false script.lua:3: division by zero
local f, err = io.open("missing.txt", "r")
if not f then print("open failed: " .. err) endEl nombre de archivo y el número de línea del mensaje de error dependen de dónde se ejecute el código. assert(value, message) lanza un error cuando value es false o nil y es una forma breve de comprobar resultados.
Un programa pequeño y completo: conteo de palabras
Este programa cuenta las palabras de un texto con una búsqueda de patrones, las ordena por frecuencia e imprime las tres primeras. Usa patrones de cadenas, tablas, ordenación con un comparador personalizado y formato de cadenas.
local text = [[
The cat and the dog. The dog sat,
and the cat ran.
]]
local counts = {}
for word in text:lower():gmatch("%a+") do
counts[word] = (counts[word] or 0) + 1
end
local list = {}
for word, n in pairs(counts) do
list[#list + 1] = {word = word, n = n}
end
table.sort(list, function(a, b)
if a.n ~= b.n then return a.n > b.n end
return a.word < b.word
end)
for i = 1, 3 do
print(string.format("%-4s %d", list[i].word, list[i].n))
end
-- the 4
-- and 2
-- cat 2Siguientes pasos
- El Lua Reference Manual en lua.org, breve y completo.
- Programming in Lua, de Roberto Ierusalimschy, uno de los creadores de Lua; la primera edición es gratuita en línea.
- La documentación de tu entorno anfitrión, como la guía de Lua de Neovim, LÖVE o la documentación de Luau de Roblox.
- LuaRocks, el gestor de paquetes para módulos de Lua.
Preguntas frecuentes
¿Por qué los arreglos de Lua empiezan en 1?
Los diseñadores de Lua eligieron la indexación desde 1 para ajustarse a las convenciones matemáticas y de las personas que no programan. Las funciones de la biblioteca estándar, como ipairs, # y table.insert, suponen que las secuencias empiezan en 1.
¿Lua es más rápido que Python?
El intérprete estándar de Lua es pequeño y, en general, rápido para un lenguaje dinámico, y LuaJIT es mucho más rápido en muchas cargas de trabajo. La velocidad real depende de la tarea, así que mide tu propio caso.
¿Cuál es la diferencia entre pairs e ipairs?
ipairs recorre la parte de arreglo en orden desde el índice 1 hasta el primer nil. pairs visita todas las claves de la tabla en un orden no especificado.
¿Qué es Luau?
Luau es un lenguaje derivado de Lua 5.1 y desarrollado por Roblox. Añade tipado gradual y mejoras de rendimiento, y se usa en los juegos de Roblox.
¿Lua es bueno para principiantes?
Sí. Tiene una sintaxis pequeña y coherente y pocos conceptos, por eso es popular para crear mods de videojuegos y para la enseñanza. Su biblioteca estándar mínima hace que dependas del programa anfitrión o de módulos para tener más funciones.