Funzioni in Lua
Le funzioni sono uno dei pilastri fondamentali di Lua. In Lua le funzioni sono valori di prima classe: possono essere assegnate a variabili, passate come argomenti e restituite da altre funzioni. In questa guida esploreremo tutti gli aspetti delle funzioni in Lua, dalla dichiarazione di base fino alle funzioni variadiche e alle closure.
Dichiarazione di una Funzione
La sintassi base per dichiarare una funzione in Lua e’ la seguente:
function nomeFunzione(parametri)
-- corpo della funzione
end
Ecco un esempio semplice:
function saluta(nome)
print("Ciao, " .. nome .. "!")
end
saluta("Marco")
-- Output: Ciao, Marco!
In realta’, la sintassi sopra e’ uno zucchero sintattico per:
saluta = function(nome)
print("Ciao, " .. nome .. "!")
end
Questo dimostra che le funzioni in Lua sono semplicemente valori assegnati a variabili.
Parametri e Argomenti
Le funzioni possono accettare zero o piu’ parametri. In Lua, se si passano piu’ argomenti del necessario, quelli in eccesso vengono ignorati. Se se ne passano meno, i parametri mancanti assumono il valore nil:
function mostra(a, b, c)
print(a, b, c)
end
mostra(1, 2, 3) -- Output: 1 2 3
mostra(1, 2) -- Output: 1 2 nil
mostra(1, 2, 3, 4) -- Output: 1 2 3 (il 4 viene ignorato)
Valori di Default
Lua non ha parametri con valori di default nativi, ma si puo’ simulare questo comportamento:
function connetti(host, porta)
host = host or "localhost"
porta = porta or 8080
print("Connessione a " .. host .. ":" .. porta)
end
connetti() -- Connessione a localhost:8080
connetti("esempio.com") -- Connessione a esempio.com:8080
connetti("esempio.com", 3000) -- Connessione a esempio.com:3000
Valori di Ritorno
Le funzioni possono restituire valori con l’istruzione return:
function somma(a, b)
return a + b
end
local risultato = somma(10, 20)
print(risultato) -- Output: 30
Ritorni Multipli
Una caratteristica distintiva di Lua e’ la possibilita’ di restituire piu’ valori da una funzione:
function dividi(dividendo, divisore)
local quoziente = math.floor(dividendo / divisore)
local resto = dividendo % divisore
return quoziente, resto
end
local q, r = dividi(17, 5)
print("Quoziente: " .. q .. ", Resto: " .. r)
-- Output: Quoziente: 3, Resto: 2
I ritorni multipli sono molto utili per restituire un risultato insieme a uno stato di errore:
function apri_file(percorso)
local file = io.open(percorso, "r")
if not file then
return nil, "Impossibile aprire il file: " .. percorso
end
return file, nil
end
local f, errore = apri_file("dati.txt")
if not f then
print("Errore: " .. errore)
end
Funzioni Variadiche
Le funzioni variadiche accettano un numero variabile di argomenti, indicati con ... (tre puntini):
function stampa_tutti(...)
local args = {...}
for i, v in ipairs(args) do
print(i .. ": " .. tostring(v))
end
end
stampa_tutti("mela", "banana", "arancia")
-- Output:
-- 1: mela
-- 2: banana
-- 3: arancia
Si possono combinare parametri fissi con quelli variadici:
function log(livello, ...)
local messaggi = {...}
for _, msg in ipairs(messaggi) do
print("[" .. livello .. "] " .. msg)
end
end
log("INFO", "Server avviato", "Porta 8080 in ascolto")
-- Output:
-- [INFO] Server avviato
-- [INFO] Porta 8080 in ascolto
Per conoscere il numero di argomenti variadici si usa select("#", ...):
function conta_args(...)
print("Numero di argomenti: " .. select("#", ...))
end
conta_args(1, nil, 3) -- Output: Numero di argomenti: 3
Funzioni come Valori di Prima Classe
In Lua le funzioni sono valori come numeri o stringhe. Possono essere assegnate a variabili, memorizzate in tabelle e passate come argomenti:
-- Assegnare una funzione a una variabile
local raddoppia = function(x) return x * 2 end
print(raddoppia(5)) -- Output: 10
-- Passare una funzione come argomento
function applica(fn, valore)
return fn(valore)
end
print(applica(raddoppia, 7)) -- Output: 14
-- Memorizzare funzioni in una tabella
local operazioni = {
somma = function(a, b) return a + b end,
sottrai = function(a, b) return a - b end,
moltiplica = function(a, b) return a * b end,
}
print(operazioni.somma(3, 4)) -- Output: 7
print(operazioni.moltiplica(3, 4)) -- Output: 12
Funzioni Anonime
Le funzioni anonime (lambda) sono funzioni senza nome, spesso usate come callback:
local numeri = {5, 2, 8, 1, 9, 3}
table.sort(numeri, function(a, b)
return a > b -- ordine decrescente
end)
for _, v in ipairs(numeri) do
print(v)
end
-- Output: 9, 8, 5, 3, 2, 1
Funzioni Locali
Le funzioni dichiarate con local sono visibili solo nello scope corrente. E’ buona pratica utilizzare funzioni locali quando possibile:
local function calcola_area(base, altezza)
return (base * altezza) / 2
end
print(calcola_area(10, 5)) -- Output: 25
Per le funzioni ricorsive locali, e’ necessario dichiarare la variabile prima della definizione:
local fattoriale
fattoriale = function(n)
if n <= 1 then return 1 end
return n * fattoriale(n - 1)
end
print(fattoriale(6)) -- Output: 720
Oppure si puo’ usare la forma abbreviata local function, che gestisce automaticamente questo caso:
local function fattoriale(n)
if n <= 1 then return 1 end
return n * fattoriale(n - 1)
end
Sintassi di Chiamata: Punto vs Due Punti
Quando le funzioni sono memorizzate nelle tabelle, Lua offre due sintassi di chiamata:
- Punto (
.): chiamata standard, si passa esplicitamente l’oggetto. - Due punti (
:): zucchero sintattico che passa automaticamente la tabella come primo parametroself.
local giocatore = {
nome = "Luigi",
vita = 100,
}
function giocatore.saluta(self)
print("Sono " .. self.nome)
end
-- Equivalente con la sintassi dei due punti
function giocatore:prendi_danno(danno)
self.vita = self.vita - danno
print(self.nome .. " ha ora " .. self.vita .. " HP")
end
giocatore.saluta(giocatore) -- Sono Luigi
giocatore:prendi_danno(25) -- Luigi ha ora 75 HP
-- Le due forme sono intercambiabili:
giocatore.prendi_danno(giocatore, 10) -- Luigi ha ora 65 HP
giocatore:saluta() -- Sono Luigi
Closure
Le funzioni in Lua possono catturare variabili dallo scope esterno, creando delle closure:
function crea_contatore(inizio)
local conteggio = inizio or 0
return function()
conteggio = conteggio + 1
return conteggio
end
end
local contatore = crea_contatore(0)
print(contatore()) -- Output: 1
print(contatore()) -- Output: 2
print(contatore()) -- Output: 3
Conclusioni
Le funzioni in Lua sono estremamente flessibili grazie alla loro natura di valori di prima classe. La possibilita’ di restituire piu’ valori, di creare funzioni variadiche e di utilizzare closure rende Lua un linguaggio potente e espressivo. Comprendere la differenza tra la sintassi con il punto e quella con i due punti e’ essenziale per lavorare con le tabelle come oggetti. L’uso di funzioni locali e’ una buona pratica che migliora le prestazioni e la leggibilita’ del codice.