Indexation et structure des tables
Contrairement à de nombreux langages C-like, Lua utilise une indexation à base 1 pour ses séquences. Les tables constituent la seule structure de données native, fonctionnant simultanément comme des tableaux et des dictionnaires associatifs.
local repertoire = {
[0] = 10, -- Clé numérique explicite
identifiant = 42, -- Clé chaîne implicite
["code_postal"] = "75001"
}
print(repertoire[0])
print(repertoire["code_postal"])
print(repertoire["identifiant"])
print(repertoire.identifiant) -- Syntaxe abrégée
Opérations sur les chaînes
La manipulation textuelle repose sur l'opérateur de concaténation .. et un ensemble de fonctions natives. La conversion de type s'effectue via tostring() et tonumber().
local prefixe = "Utilisateur_"
local id_session = 804
-- Concaténation et conversion implicite
local etiquette = prefixe .. tostring(id_session)
-- Longueur et transformation de casse
local texte_original = "Données_CRITIQUES"
local longueur = string.len(texte_original)
local texte_normalise = string.lower(texte_original)
-- Extraction et formatage
local sous_chaine = string.sub(texte_original, 1, 7)
local message_formate = string.format("Taille: %d, Extraits: %s", longueur, sous_chaine)
Pour la recherche et le remplacement, string.find localise un motif tandis que string.gsub effectue des substitutions. Le quatrième paramètre de gsub limite le nombre de remplacements.
local phrase = "Système d'exploitation Linux"
local resultat = string.gsub(phrase, "Linux", "Windows", 1) -- Un seul remplacement
Parcours et agrégation de données
Une table Lua mélange des parties séquentielles et associatives. L'opérateur # retourne uniquement la longueur de la partie tableau contiguë.
local mesures = {10, 25, 30, 45, 50}
mesures[8] = 99 -- Création d'une entrée discontinue
-- Parcours séquentiel sécurisé
for idx = 1, #mesures do
print(mesures[idx])
end
-- Itération avec ipairs (arrête aux premiers trous)
for indice, valeur in ipairs(mesures) do
print(indice, valeur)
end
-- Itération exhaustive avec pairs (inclut les clés non séquentielles)
for cle, contenu in pairs(mesures) do
print(cle, contenu)
end
La fonction table.unpack (anciennement unpack) permet de désagréger un tableau en arguments multiples, utile pour le repositionnement ou l'appel de fonctions variadiques.
local serie_temporelle = {20, 45, 80, 120, 160}
local _, _, valeur_mediane, pic = table.unpack(serie_temporelle)
print(valeur_mediane, pic) -- Retourne 80, 120
Chargement de scripts et encapsulation
La fonction require charge et exécute un script une seule fois, le mettant en cache. Elle retourne la valeur finale retournée par le fichier. Pour exposer des fonctionnalités, il est recommandé de retourner une table contenant les méthodes publiques.
-- Dans utils.lua
local outils = {}
function outils.calculer_somme(a, b) return a + b end
return outils
-- Dans le fichier principal
local module_utilitaire = require("utils")
print(module_utilitaire.calculer_somme(10, 5))
Sémantique du point et des deux-points
La distinction entre . et : réside dans la gestion implicite du contexte self. Le deux-points injecte automatiquement la table appelante comme premier argument, tandis que le point exige une transmission explicite.
local controleur = {}
-- Définition avec point : requiert 'contexte' explicitement
function controleur.initialiser(contexte, parametre)
print("Initialisation via point", contexte, parametre)
end
-- Définition avec deux-points : 'self' est injecté automatiquement
function controleur:lancer(mode)
print("Exécution via deux-points", self, mode)
end
controleur.initialiser(controleur, "valeur") -- Appel standard
controleur:lancer("actif") -- self pointe sur controleur
controleur.lancer(controleur, "actif") -- Équivalent explicite
Une incohérence entre la définition et l'appel (par exemple définir avec : mais appeler avec .) entraîne une perte de référence self, souvent évaluée à nil.
Métatables et résolution dynamique
Les métatables interceptent les opérations absentes dans la table cible. Le champ \_\_index est crucial : si une clé n'existe pas dans la table primaire, l'interpréteur consulte la métatable.
local entite_vide = {}
local configuration_par_defaut = {
__index = {
niveau_vie = 100,
vitesse = 5.5,
etat = "inactif"
}
}
setmetatable(entite_vide, configuration_par_defaut)
print(entite_vide.niveau_vie) -- Retourne 100 via résolution __index
Modélisation orientée objet
Vue l'absence de classes natives, Lua simule la POO en chaînant les métatables. Un constructeur attache la table classe comme \_\_index de l'instance.
local Entite = {}
Entite.__index = Entite
function Entite:nouveau(nom)
local instance = setmetatable({}, self)
instance.titulaire = nom
return instance
end
function Entite:afficher_identite()
print("Identité :", self.titulaire)
end
local personnage = Entite:nouveau("Aventurier")
personnage:afficher_identite()
Héritage et sucrharge de méthodes
L'héritage se construit en faisant pointer \_\_index du dérivé vers la classe mère. Lors d'un appel de méthode, Lua remonte la chaîne des métatables jusqu'à trouver une implémentation.
local Personnage = Entite -- Hérite de la structure précédente
function Personnage:attaquer()
print(self.titulaire .. " frappe avec une épée")
end
-- Définition du dérivé
local Archer = setmetatable({}, {__index = Personnage})
Archer.__index = Archer
function Archer:nouveau(nom)
local instance = setmetatable({}, self)
instance.titulaire = nom
return instance
end
function Archer:attaquer()
print(self.titulaire .. " tire une flèche")
end
local archer = Archer:nouveau("Legolas")
archer:attaquer() -- Résolu dans Archer
archer:afficher_identite() -- Résolu dans Entite via le chaînage
Lorsqu'une méthode est redéfinie dans le dérivé, elle masque la version parente. Pour invoquer explicitement la logique de la classe mère tout en préservant le contexte actuel, il faut utiliser la notation pointée et transmettre manuellement l'instance :
function Archer:attaquer()
print(self.titulaire .. " tire une flèche")
Personnage.attaquer(self) -- Appel explicite vers la classe mère
end
Cette approche garantit que le parent opère sur les données de l'instance fille, respectant les principes de polymorphisme et de délégation propre au modèle objet Lua.