Tabelle in Lua
Le tabelle sono l’unica struttura dati presente in Lua e rappresentano il cuore del linguaggio. Con le tabelle si possono costruire array, dizionari, oggetti, moduli e molto altro. In questa guida esploreremo tutti gli aspetti delle tabelle, dalla creazione all’iterazione, passando per le funzioni della libreria table e la semantica per riferimento.
Cos’e’ una Tabella
Una tabella in Lua e’ un array associativo: una struttura dati che associa chiavi a valori. Le chiavi possono essere di qualsiasi tipo tranne nil, e anche i valori possono essere di qualsiasi tipo. Le tabelle si creano con il costruttore {}:
local tabella_vuota = {}
Tabelle come Array
Quando si usano chiavi numeriche intere consecutive a partire da 1, la tabella si comporta come un array. Nota importante: in Lua gli indici partono da 1, non da 0:
local frutti = {"mela", "banana", "arancia", "uva"}
print(frutti[1]) -- Output: mela
print(frutti[3]) -- Output: arancia
print(frutti[4]) -- Output: uva
Si possono aggiungere elementi ad un array assegnando valori a nuovi indici:
local numeri = {10, 20, 30}
numeri[4] = 40
numeri[5] = 50
print(numeri[5]) -- Output: 50
Lunghezza di un Array
L’operatore # restituisce la lunghezza di un array (il numero di elementi con indici consecutivi a partire da 1):
local colori = {"rosso", "verde", "blu"}
print(#colori) -- Output: 3
colori[4] = "giallo"
print(#colori) -- Output: 4
Attenzione: l’operatore # non e’ affidabile se la tabella ha “buchi” (indici non consecutivi).
Tabelle come Dizionari
Usando chiavi stringa, le tabelle funzionano come dizionari (o mappe):
local persona = {
nome = "Anna",
cognome = "Rossi",
eta = 28,
citta = "Milano"
}
-- Accesso con la notazione punto
print(persona.nome) -- Output: Anna
print(persona.eta) -- Output: 28
-- Accesso con la notazione parentesi quadre
print(persona["citta"]) -- Output: Milano
La notazione con le parentesi quadre e’ necessaria quando la chiave contiene spazi, caratteri speciali o e’ memorizzata in una variabile:
local chiave = "nome"
print(persona[chiave]) -- Output: Anna
local dati = {}
dati["nome completo"] = "Anna Rossi"
print(dati["nome completo"]) -- Output: Anna Rossi
Aggiungere e Rimuovere Chiavi
Per aggiungere una nuova coppia chiave-valore basta assegnare un valore. Per rimuoverla, si assegna nil:
local config = {tema = "scuro"}
config.lingua = "italiano" -- aggiunta
config.notifiche = true -- aggiunta
print(config.lingua) -- Output: italiano
config.notifiche = nil -- rimozione
print(config.notifiche) -- Output: nil
Tabelle Miste
Una tabella puo’ contenere sia elementi con indice numerico sia coppie chiave-valore stringa:
local mista = {
"primo", -- indice 1
"secondo", -- indice 2
nome = "test", -- chiave stringa
attivo = true, -- chiave stringa
"terzo", -- indice 3
}
print(mista[1]) -- Output: primo
print(mista[3]) -- Output: terzo
print(mista.nome) -- Output: test
print(#mista) -- Output: 3 (conta solo gli indici numerici)
Tabelle Nidificate
Le tabelle possono contenere altre tabelle, creando strutture dati complesse:
local scuola = {
{
classe = "1A",
studenti = {"Marco", "Giulia", "Luca"},
voti_medi = {Marco = 7.5, Giulia = 9.0, Luca = 6.5}
},
{
classe = "2B",
studenti = {"Sara", "Paolo"},
voti_medi = {Sara = 8.0, Paolo = 7.0}
}
}
-- Accesso ai dati nidificati
print(scuola[1].classe) -- Output: 1A
print(scuola[1].studenti[2]) -- Output: Giulia
print(scuola[1].voti_medi.Giulia) -- Output: 9.0
Funzioni della Libreria table
Lua fornisce la libreria table con funzioni utili per manipolare le tabelle usate come array.
table.insert
Inserisce un elemento in una tabella. Senza specificare la posizione, l’elemento viene aggiunto alla fine:
local lista = {"a", "b", "c"}
table.insert(lista, "d") -- aggiunge alla fine
print(lista[4]) -- Output: d
table.insert(lista, 2, "x") -- inserisce alla posizione 2
-- lista ora e': {"a", "x", "b", "c", "d"}
print(lista[2]) -- Output: x
table.remove
Rimuove un elemento dalla tabella e lo restituisce. Senza specificare la posizione, rimuove l’ultimo elemento:
local lista = {"a", "b", "c", "d"}
local ultimo = table.remove(lista) -- rimuove "d"
print(ultimo) -- Output: d
local rimosso = table.remove(lista, 1) -- rimuove "a"
print(rimosso) -- Output: a
-- lista ora e': {"b", "c"}
table.sort
Ordina una tabella sul posto. Di default ordina in modo crescente:
local numeri = {42, 15, 8, 23, 4, 16}
table.sort(numeri)
for _, v in ipairs(numeri) do
print(v)
end
-- Output: 4, 8, 15, 16, 23, 42
Si puo’ passare una funzione di confronto personalizzata:
local parole = {"banana", "mela", "arancia", "uva"}
-- Ordine decrescente per lunghezza
table.sort(parole, function(a, b)
return #a > #b
end)
for _, p in ipairs(parole) do
print(p)
end
-- Output: arancia, banana, mela, uva
table.concat
Unisce gli elementi di un array in una stringa, con un separatore opzionale:
local parole = {"Lua", "e'", "fantastico"}
local frase = table.concat(parole, " ")
print(frase) -- Output: Lua e' fantastico
Iterare sulle Tabelle
Per iterare su una tabella si usano ipairs (per gli array) e pairs (per tutte le chiavi):
local inventario = {
spada = 1,
scudo = 2,
pozione = 5,
frecce = 20,
}
-- Iterazione con pairs (tutte le chiavi)
print("Inventario:")
for oggetto, quantita in pairs(inventario) do
print(" " .. oggetto .. ": " .. quantita)
end
-- Iterazione con ipairs (solo indici numerici consecutivi)
local azioni = {"attacca", "difendi", "cura", "fuggi"}
print("\nAzioni disponibili:")
for i, azione in ipairs(azioni) do
print(" " .. i .. ". " .. azione)
end
Semantica per Riferimento
Le tabelle in Lua sono passate per riferimento. Quando si assegna una tabella a un’altra variabile, entrambe le variabili puntano alla stessa tabella in memoria:
local originale = {1, 2, 3}
local copia = originale -- NON crea una copia!
copia[1] = 99
print(originale[1]) -- Output: 99 (modificato!)
-- Verifica che sono la stessa tabella
print(originale == copia) -- Output: true
Per creare una copia effettiva di una tabella, bisogna copiarla manualmente:
function copia_tabella(t)
local nuova = {}
for k, v in pairs(t) do
nuova[k] = v
end
return nuova
end
local originale = {1, 2, 3}
local copia = copia_tabella(originale)
copia[1] = 99
print(originale[1]) -- Output: 1 (non modificato)
print(copia[1]) -- Output: 99
print(originale == copia) -- Output: false (sono tabelle diverse)
Esempio Pratico: Rubrica Telefonica
Ecco un esempio completo che mette insieme i concetti visti:
local rubrica = {}
-- Funzione per aggiungere un contatto
local function aggiungi(nome, telefono)
table.insert(rubrica, {nome = nome, telefono = telefono})
end
-- Aggiungere contatti
aggiungi("Marco", "333-1234567")
aggiungi("Anna", "340-7654321")
aggiungi("Luigi", "328-9876543")
-- Ordinare per nome
table.sort(rubrica, function(a, b)
return a.nome < b.nome
end)
-- Stampare la rubrica
print("Rubrica telefonica:")
for i, contatto in ipairs(rubrica) do
print(i .. ". " .. contatto.nome .. " - " .. contatto.telefono)
end
-- Output:
-- 1. Anna - 340-7654321
-- 2. Luigi - 328-9876543
-- 3. Marco - 333-1234567
Conclusioni
Le tabelle sono la struttura dati universale di Lua: con esse si possono costruire array, dizionari, oggetti e qualsiasi altra struttura complessa. Comprendere la differenza tra l’uso come array (indici numerici da 1) e come dizionario (chiavi stringa) e’ fondamentale. Le funzioni della libreria table semplificano le operazioni comuni, e la consapevolezza della semantica per riferimento previene errori comuni nella manipolazione dei dati.