Dashboard HTML CSS JavaScript Lua 5.4 Lua 5.5 Éditeur Documentation
</> Cours Lua 5.5

Cours Lua 5.5

Découvrez les nouveautés de Lua 5.5 : attributs <const> et <close>, to-be-closed variables, et gestion avancée des ressources.

0/12 leçons terminées

1. Introduction à Lua 5.5

Lua 5.5 est la dernière évolution majeure du langage Lua. Elle introduit des mécanismes puissants de gestion des ressources et de constance, tout en conservant la philosophie de simplicité et de légèreté qui fait la renommée de Lua.

Historique et contexte

Lua 5.5 a été annoncé par l'équipe de la PUC-Rio comme la suite naturelle de Lua 5.4 (sorti en 2020). Les principaux objectifs de cette nouvelle version sont : améliorer la gestion automatique des ressources grâce aux variables <close>, renforcer la sécurité du code avec <const>, et affiner les performances du VM.

-- Comparaison rapide entre Lua 5.4 et Lua 5.5
-- Lua 5.4 : pas d'attributs de variables
local x = 10   -- x peut être réassignée
x = 20          -- pas d'erreur

-- Lua 5.5 : attributs de variables
local <const> PI = 3.14159  -- PI est constante
-- PI = 3.0  → erreur : assignment to a read-only variable

Ce qui change par rapport à Lua 5.4

  • Attributs de variables : <const> pour les constantes, <close> pour les variables à fermeture automatique.
  • Variables to-be-closed : nettoyage automatique des ressources (fichiers, connexions, verrous) en fin de bloc, similaire au try/finally ou defer.
  • Améliorations aux boucles : nouveaux patrons d'itération et meilleur comportement des labels.
  • Fonctions améliorées : attributs sur les fonctions, meilleurs messages d'erreur.
  • Performance du VM : optimisations bytecode, meilleure collecte d'ordures.

Rétrocompatibilité

Lua 5.5 reste largement rétrocompatible avec Lua 5.4. La plupart des scripts écrits en Lua 5.4 fonctionneront sans modification. Les changements incompatibles sont minimes et documentés dans les notes de la release.

-- Un script Lua 5.4 fonctionne en Lua 5.5
local tab = {1, 2, 3, 4, 5}
for i, v in ipairs(tab) do
    print(i, v)
end

-- Les nouvelles fonctionnalités sont optionnelles
-- Vous pouvez les adopter progressivement

Installation

Pour installer Lua 5.5, vous pouvez compiler à partir des sources officiels ou utiliser un gestionnaire de paquets :

-- Compilation depuis les sources
-- git clone https://github.com/lua/lua.git
-- cd lua && git checkout v5.5.0
-- make linux (ou make macosx, make mingw...)

-- Vérification de la version
-- lua -v
-- Lua 5.5.0  Copyright (C) 1994-2026 Lua.org, PUC-Rio

-- Vérifier la version dans le REPL
print(_VERSION)  --> "Lua 5.5"

Aperçu du cours

Ce cours couvrira en profondeur chaque nouveauté de Lua 5.5. Nous explorerons les attributs de variables, les variables to-be-closed, les améliorations aux boucles et fonctions, la gestion des erreurs, les générateurs, l'interopérabilité C, les optimisations de performance et les patterns avancés.

-- Un aperçu de ce que nous allons apprendre :
local <const> VERSION = "5.5"
local <close> fichier = io.open("donnees.txt", "r")

if fichier then
    local contenu = fichier:read("*a")
    print("Lua " .. VERSION .. " : " .. #contenu .. " octets")
    -- Le fichier sera automatiquement fermé en fin de bloc
end

Récapitulatif

  • Lua 5.5 introduit <const>, <close> et les variables to-be-closed.
  • Rétrocompatible avec Lua 5.4 pour la plupart des scripts.
  • Objectif principal : meilleure gestion des ressources et sécurité.
  • Installation depuis les sources ou via LuaRocks.
  • Chaque nouveauté est optionnelle, adoption progressive possible.

2. Les attributs de variables (<const> et <close>)

Lua 5.5 introduit les attributs de variables, un mécanisme qui permet de qualifier le comportement d'une variable locale lors de sa déclaration. Les deux attributs principaux sont <const> et <close>.

L'attribut <const>

Une variable déclarée avec <const> ne peut plus être réassignée après son initialisation. Toute tentative de modification provoque une erreur à l'exécution.

-- Déclaration d'une constante
local <const> MAX_UTILISATEURS = 100
local <const> NOM_APPLICATION = "MonApp"

print(MAX_UTILISATEURS)  --> 100
print(NOM_APPLICATION)   --> "MonApp"

-- Tentative de réassignation → ERREUR
-- MAX_UTILISATEURS = 200
-- Erreur : attempt to assign to a read-only variable

<const> sur les fonctions

L'attribut <const> peut également être appliqué aux fonctions locales, empêchant leur réassignation.

-- Fonction constante
local <const> function calculerTVA(montant)
    return montant * 0.20
end

print(calculerTVA(100))  --> 20

-- On ne peut pas remplacer la fonction
-- calculerTVA = function(m) return m * 0.10 end
-- Erreur : attempt to assign to a read-only variable

Tables constantes vs référence constante

Un point important : <const> rend la variable constante, pas la table elle-même. On peut modifier le contenu d'une table constante, mais pas réassigner la variable.

-- Table constante (la référence ne peut changer)
local <const> config = {
    port = 8080,
    host = "localhost",
    debug = true
}

-- Modifier un champ : AUTORISÉ
config.debug = false
print(config.debug)  --> false

-- Ajouter un champ : AUTORISÉ
config.version = "2.0"

-- Réassigner la variable : INTERDIT
-- config = {}
-- Erreur : attempt to assign to a read-only variable

-- Pour une truly immutable table, utilisez un métaméthode
local <const> donnees = setmetatable({
    nom = "Alice",
    age = 30
}, {
    __newindex = function()
        error("Table immutable !")
    end
})
-- donnees.nom = "Bob" → erreur via __newindex

L'attribut <close> (aperçu)

L'attribut <close> marque une variable pour être automatiquement « fermée » lorsque son bloc se termine. Nous verrons ce mécanisme en détail dans la leçon 3.

-- Aperçu de <close>
do
    local <close> fichier = io.open("data.txt", "r")
    if fichier then
        local donnees = fichier:read("*a")
        print(donnees)
    end
    -- fichier automatiquement fermé ici !
end

Ordre des attributs et syntaxe

La syntaxe correcte place l'attribut entre local et le nom de la variable. On ne peut pas combiner <const> et <close> sur la même variable.

-- Syntaxe correcte
local <const> x = 10      -- correct
local <close> f = io.open("f.txt", "r")  -- correct

-- Syntaxe incorrecte
-- local <const, close> y = 42  → erreur de syntaxe

-- Const avec assignation multiple
local <const> A, B, C = 1, 2, 3
print(A, B, C)  --> 1  2  3
-- A = 5  → erreur

Cas d'utilisation de <const>

-- Constantes de configuration
local <const> TAILLE_PAGE = 20
local <const> SEPARATEUR = ";"
local <const> CODES_ERREUR = {
    INVALIDE = 400,
    NON_TROUVE = 404,
    SERVEUR = 500
}

-- Les constantes évitent les bugs d'assignation accidentelle
function paginer(resultats, page)
    local debut = (page - 1) * TAILLE_PAGE + 1
    local fin = math.min(page * TAILLE_PAGE, #resultats)
    local pageResultats = {}
    for i = debut, fin do
        table.insert(pageResultats, resultats[i])
    end
    return pageResultats
end

Récapitulatif

  • <const> empêche la réassignation d'une variable locale.
  • <close> active le nettoyage automatique en fin de bloc (détail leçon 3).
  • <const> sur une table interdit la réassignation, pas la modification du contenu.
  • On ne peut pas combiner <const> et <close> sur la même variable.
  • Les fonctions locales peuvent aussi être <const>.

3. Variables to-be-closed

Les variables to-be-closed (à fermer) sont la nouveauté la plus attendue de Lua 5.5. Elles permettent le nettoyage automatique des ressources à la fin d'un bloc, offrant un mécanisme similaire au defer de Go ou au try/finally d'autres langages.

Le problème sans to-be-closed

En Lua 5.4, la fermeture manuelle des ressources nécessite une gestion rigoureuse, ce qui peut conduire à des fuites si une erreur survient.

-- Problème : fuite de ressources si error()
local f = io.open("data.txt", "r")
if f then
    local donnees = f:read("*a")
    -- Si une erreur survient ici, f ne sera jamais fermée !
    traiter(donnees)  -- ← peut causer une erreur
    f:close()        -- ← pourrait ne jamais être atteint
end

La solution avec <close>

L'attribut <close> garantit que la méthode __close sera appelée quand le bloc se termine, que ce soit normalement ou par erreur.

-- Solution : le bloc do...end avec <close>
do
    local <close> f = io.open("data.txt", "r")
    if f then
        local donnees = f:read("*a")
        traiter(donnees)  -- même si error() est appelé ici...
    end
    -- f est automatiquement fermée ici !
end

Le protocole __close

Une variable to-be-closed doit avoir une méthode __close (c'est-à-dire un métaméthode). La fonction io.open retourne un fichier qui possède cette méthode.

-- Créer un objet avec __close
local function creerVerrou(nom)
    local verrou = {nom = nom, actif = true}
    function verrou:__close()
        if self.actif then
            print("Libération du verrou : " .. self.nom)
            self.actif = false
        end
    end
    return verrou
end

do
    local <close> monVerrou = creerVerrou("fichier_critique")
    print("Travail avec le verrou...")
end
-- Libération du verrou : fichier_critique

Nettoyage avec base de données

-- Simulation de connexion à une base de données
local function ouvrirConnexion(url)
    local conn = {
        url = url,
        ouverte = true,
        requetes = 0
    }

    function conn:executerRequete(sql)
        if not self.ouverte then
            error("Connexion fermée !")
        end
        self.requetes = self.requetes + 1
        print("Exécution : " .. sql)
        return {}
    end

    function conn:__close()
        if self.ouverte then
            print("Fermeture de la connexion (requêtes : " .. self.requetes .. ")")
            self.ouverte = false
        end
    end

    print("Connexion ouverte à " .. url)
    return conn
end

-- Utilisation
do
    local <close> db = ouvrirConnexion("mysql://localhost/ma_base")
    db:executerRequete("SELECT * FROM users")
    db:executerRequete("UPDATE users SET actif=1")
end
-- Connexion ouverte à mysql://localhost/ma_base
-- Exécution : SELECT * FROM users
-- Exécution : UPDATE users SET actif=1
-- Fermeture de la connexion (requêtes : 2)

Comparaison avec d'autres langages

  • Go : defer f.Close() — même concept de nettoyage en fin de fonction/bloc.
  • Python : with open(...) as f: — le gestionnaire de contexte est similaire.
  • C++ : std::unique_ptr et RAII — gestion automatique via destructeurs.
  • Java : try (var res = ...) {} — les try-with-resources depuis Java 7.
-- Exemple complet : pipeline de traitement de fichiers
local function traiterFichier(cheminEntree, cheminSortie)
    do
        local <close> entree = io.open(cheminEntree, "r")
        if not entree then
            error("Impossible d'ouvrir " .. cheminEntree)
        end

        local <close> sortie = io.open(cheminSortie, "w")
        if not sortie then
            error("Impossible de créer " .. cheminSortie)
        end

        for ligne in entree:lines() do
            sortie:write(string.upper(ligne) .. "\n")
        end
    end
    -- Les deux fichiers sont fermés automatiquement !
end

Erreurs et to-be-closed

Les variables to-be-closed sont nettoyées même en cas d'erreur propagée, ce qui garantit la libération des ressources.

local function demoErreur()
    do
        local <close> res = creerVerrou("temporaire")
        print("Début du traitement")
        error("Une erreur inattendue !")
        -- Le code ci-dessus ne sera jamais exécuté
    end
    -- Mais __close sera quand même appelé !
end

-- Utilisation de pcall pour capturer l'erreur
local ok, err = pcall(demoErreur)
print(ok, err)  --> false "Une erreur inattendue !"
-- La ressource a été libérée malgré l'erreur

Récapitulatif

  • <close> garantit l'appel à __close en fin de bloc, même en cas d'erreur.
  • Les variables to-be-closed doivent être déclarées dans un bloc do...end.
  • L'objet doit implémenter la métaméthode __close.
  • Similaire à defer (Go), with (Python), ou les try-with-resources (Java).
  • Permet de gérer les fichiers, verrous, connexions de base de données de manière sûre.

4. Les améliorations aux boucles

Lua 5.5 apporte des améliorations subtiles mais significatives aux boucles et au contrôle de flux, rendant le code plus prévisible et plus performant.

Améliorations de la boucle for générique

La boucle for générique bénéficie d'optimisations internes pour les itérateurs standards comme pairs et ipairs.

-- ipairs optimisé en Lua 5.5
local fruits = {"pomme", "banane", "cerise", "datte", "elderberry"}

-- ipairs bénéficie d'une meilleure optimisation interne
for i, fruit in ipairs(fruits) do
    print(i, fruit)
end

-- pairs a aussi des optimisations pour les tables non mélangées
local config = {timeout = 30, retries = 3, verbose = true}
for cle, valeur in pairs(config) do
    print(cle, valeur)
end

Comportement amélioré de break dans les boucles imbriquées

En Lua 5.5, le comportement de break dans les boucles imbriquées est mieux défini et les messages d'erreur sont plus explicites.

-- break sort de la boucle la plus interne
for i = 1, 5 do
    for j = 1, 5 do
        if i * j > 10 then
            print("Sortie à i=" .. i .. " j=" .. j)
            break
        end
    end
end

Améliorations des labels goto

Les labels ::label:: ont un comportement plus strict en Lua 5.5, avec de meilleurs messages d'erreur pour les sauts invalides.

-- goto pour sortir de blocs imbriqués
function rechercher(tableau, critere)
    for i, v in ipairs(tableau) do
        for j, val in pairs(v) do
            if val == critere then
                goto trouvé
            end
        end
    end
    print("Non trouvé")
    return nil

::trouvé::
    print("Trouvé !")
    return i
end

Itérateurs personnalisés avec coroutine.wrap

La boucle for générique s'intègre parfaitement avec les itérateurs créés via les coroutines.

-- Itérateur de plage avec pas personnalisé
local function plage(debut, fin, pas)
    pas = pas or 1
    return function()
        if debut <= fin then
            local courant = debut
            debut = debut + pas
            return courant
        end
    end
end

-- Utilisation avec la boucle for
for n in plage(0, 10, 2) do
    print(n)  -- 0, 2, 4, 6, 8, 10
end

-- Itérateur Fibonacci
local function fibonacci(max)
    local a, b = 0, 1
    return function()
        if a > max then return nil end
        local val = a
        a, b = b, a + b
        return val
    end
end

for f in fibonacci(100) do
    print(f)
end
-- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89

Numerical for avec pas négatif et bornes dynamiques

-- La boucle for numérique évalue les bornes une seule fois
local t = {10, 20, 30, 40, 50}
for i = 1, #t do
    print(i, t[i])
end

-- Parcours inversé efficace
for i = #t, 1, -1 do
    print("Inversé:", i, t[i])
end

-- La boucle for est optimisée au bytecode en Lua 5.5
-- Pas besoin de convertir les bornes à chaque itération

Récapitulatif

  • La boucle for générique bénéficie d'optimisations pour pairs et ipairs.
  • break fonctionne toujours sur la boucle la plus interne.
  • Les labels ::label:: ont de meilleurs messages d'erreur.
  • Les itérateurs personnalisés s'intègrent naturellement avec for...in.
  • La boucle numérique évalue les bornes une seule fois.

5. Les fonctions améliorées

Lua 5.5 apporte des améliorations significatives aux fonctions, notamment la possibilité de leur appliquer des attributs et des messages d'erreur plus informatifs.

Fonctions avec attribut <const>

Comme les variables, les fonctions locales peuvent être déclarées <const> pour empêcher leur réassignation.

-- Fonction constante
local <const> function calculerMoyenne(notes)
    local somme = 0
    for _, note in ipairs(notes) do
        somme = somme + note
    end
    return somme / #notes
end

print(calculerMoyenne({12, 15, 18, 14}))  --> 14.75

-- On ne peut pas remplacer cette fonction
-- calculerMoyenne = function(t) ... end
-- Erreur : attempt to assign to a read-only variable

Meilleurs messages d'erreur

Lua 5.5 produit des messages d'erreur plus informatifs, incluant souvent le nom de la fonction et le fichier source.

-- En Lua 5.4, l'erreur peut être peu claire
-- En Lua 5.5, le traceback est plus détaillé

local function fonctionA()
    return fonctionB()
end

local function fonctionB()
    return fonctionC()
end

local function fonctionC()
    error("une erreur survenue")
end

local ok, err = pcall(fonctionA)
print(ok)   --> false
print(err)  -- traceback détaillé avec noms de fonctions et numéros de ligne

Valeurs de retour multiples améliorées

Le comportement des valeurs de retour multiples est plus prévisible dans Lua 5.5, notamment lors de leur utilisation comme arguments.

-- Les valeurs multiples dans les appels de fonctions
local function obtenirCoordonnees()
    return 10, 20, 30
end

-- Utilisation directe comme arguments
print(obtenirCoordonnees())  --> 10  20  30

-- Dans une table avec table.pack
local coords = table.pack(obtenirCoordonnees())
print(coords.n)  --> 3

-- table.unpack pour déballer
print(table.unpack(coords, 1, coords.n))  --> 10  20  30

Les closures améliorées

Les closures (fermetures) sont plus performantes en Lua 5.5 grâce aux optimisations du VM.

-- Closure avec <const> pour les paramètres configurables
local function creerCompresseur(algorithme, niveaux)
    local <const> ALGO = algorithme
    local <const> NIVEAUX_MAX = niveaux

    return function(donnees)
        print("Compression avec " .. ALGO .. " (niveau " .. NIVEAUX_MAX .. ")")
        return donnees
    end
end

local lz77 = creerCompresseur("LZ77", 9)
lz77("données à compresser")
-- Compression avec LZ77 (niveau 9)

Appels de fonctions et syntaxe

-- Syntaxe d'appel avec options par défaut
local function traiterOptions(opts)
    opts = opts or {}
    local <const> defauts = {
        verbose = false,
        timeout = 30,
        retries = 3
    }
    for k, v in pairs(defauts) do
        if opts[k] == nil then
            opts[k] = v
        end
    end
    return opts
end

local config = traiterOptions({verbose = true})
print(config.verbose, config.timeout, config.retries)
-- true  30  3

Récapitulatif

  • Les fonctions locales peuvent porter l'attribut <const>.
  • Les messages d'erreur contiennent plus d'informations sur la pile d'appels.
  • Les closures sont plus performantes grâce aux optimisations VM.
  • Le comportement des valeurs de retour multiples est plus prévisible.
  • Les attributs sur les fonctions améliorent la sécurité du code.

6. Tables et nouvelles fonctionnalités

Les tables restent la structure de données centrale de Lua 5.5, mais plusieurs améliorations les rendent plus robustes et plus pratiques.

table.pack et table.unpack améliorés

Les fonctions table.pack et table.unpack ont été affinées pour un meilleur comportement avec les valeurs nil intermédiaires.

-- table.pack préserve le champ .n
local t = table.pack(1, 2, nil, 4, 5)
print(t.n)        --> 5 (nombre d'arguments)
print(#t)         --> 2 (nil coupe la longueur)
print(t[3])       --> nil

-- table.unpack avec plage précise
local a, b, c = table.unpack(t, 1, t.n)
print(a, b, c)    --> 1  2  nil

-- Extraire une sous-plage
local sub = {table.unpack(t, 2, 4)}
print(#sub)        --> 2

Le problème du # et les améliorations 5.5

L'opérateur # peut avoir un comportement imprévisible avec les tables contenant des « trous » (nil intermédiaires). Lua 5.5 offre un comportement légèrement plus prévisible.

-- # est bien défini pour les tableaux sans trous
local tab = {1, 2, 3, 4, 5}
print(#tab)  --> 5 (garanti)

-- Avec des trous : comportement défini entre deux bornes
local tab2 = {1, 2, nil, 4, 5}
print(#tab2)  --> 2 ou 5 (défini comme entre les deux)

-- Utilisez table.pack pour un comptage fiable
local safe = table.pack(1, 2, nil, 4)
print(safe.n)  --> 4 (toujours fiable)

table.next amélioré

La fonction table.next (utilisée en interne par pairs) bénéficie d'optimisations en Lua 5.5.

-- table.next pour une itération manuelle
local fruits = {pomme = 5, banane = 3, cerise = 8}

local cle = nil
while true do
    cle = table.next(fruits, cle)
    if cle == nil then break end
    print(cle, fruits[cle])
end

-- En Lua 5.5, table.next peut recevoir un hint
-- pour commencer à un point spécifique dans la table

Les métatables et __close sur les tables

En Lua 5.5, les tables peuvent être utilisées comme variables to-be-closed si elles implémentent __close.

-- Table avec nettoyage automatique
local function creerRessource(nom)
    local res = {nom = nom, active = true}
    function res:__close()
        self.active = false
        print("Ressource '" .. self.nom .. "' libérée")
    end
    return res
end

do
    local <close> r1 = creerRessource("base_données")
    local <close> r2 = creerRessource("cache")
    print("Utilisation des ressources...")
end
-- Ressource 'cache' libérée
-- Ressource 'base_données' libérée
-- (ordre inverse de déclaration)

Table.clone (si disponible)

Certaines implémentations de Lua 5.5 ajoutent table.clone pour copier superficiellement des tables.

-- Table.clone pour une copie superficielle
local original = {nom = "Alice", scores = {10, 20, 30}}

if table.clone then
    local copie = table.clone(original)
    copie.nom = "Bob"
    print(original.nom)  --> "Alice" (non modifié)
    print(copie.nom)     --> "Bob"
    -- attention : scores partagé (copie superficielle)
end

-- Copie profonde manuelle si table.clone n'existe pas
local function copieProfonde(t)
    if type(t) ~= "table" then return t end
    local res = {}
    for k, v in pairs(t) do
        res[copieProfonde(k)] = copieProfonde(v)
    end
    return setmetatable(res, getmetatable(t))
end

Récapitulatif

  • table.pack/table.unpack sont plus fiables avec les nil intermédiaires.
  • # est bien défini pour les tableaux sans trous.
  • table.next bénéficie d'optimisations internes.
  • Les tables peuvent implémenter __close pour le nettoyage automatique.
  • table.clone (si disponible) offre une copie superficielle pratique.

7. Gestion des erreurs avancée

Lua 5.5 améliore la gestion des erreurs avec de meilleurs outils pour le débogage, des messages plus informatifs et des mécanismes de récupération plus robustes.

pcall et xpcall améliorés

Les fonctions pcall et xpcall sont essentielles pour la gestion des erreurs. Lua 5.5 améliore leur comportement et leurs messages.

-- pcall : appel protégé basique
local ok, resultat = pcall(function()
    return 2 + 2
end)
print(ok, resultat)  --> true  4

-- pcall avec erreur
local ok, err = pcall(function()
    error({code = 404, message = "Non trouvé"})
end)
print(ok)          --> false
print(err.message)  --> "Non trouvé"

xpcall avec handler d'erreur

xpcall accepte un second argument : une fonction de traitement d'erreur qui transforme l'erreur avant de la retourner.

-- xpcall avec un handler d'erreur personnalisé
local function traiterErreur(err)
    return {
        niveau = "CRITIQUE",
        erreur = tostring(err),
        horodatage = os.date("%Y-%m-%d %H:%M:%S")
    }
end

local ok, err = xpcall(function()
    error("panne du disque")
end, traiterErreur)

if not ok then
    print(err.niveau)      --> "CRITIQUE"
    print(err.erreur)      --> "panne du disque"
    print(err.horodatage)  --> "2026-07-22 14:30:00"
end

Traceback détaillé

debug.traceback fournit une pile d'appels complète, utile pour le débogage.

local function niveau3()
    error("erreur en niveau 3")
end

local function niveau2()
    niveau3()
end

local function niveau1()
    niveau2()
end

-- Avec xpcall et debug.traceback
local ok, err = xpcall(niveau1, function(e)
    return debug.traceback(e, 2)
end)

print(err)
-- traceback:
--   main.lua:10: in function 'niveau2'
--   main.lua:14: in function 'niveau1'

La bibliothèque debug améliorée

La bibliothèque debug offre plus d'outils pour l'inspection du runtime.

-- debug.getinfo : informations sur une fonction
local function maFonction() end
local info = debug.getinfo(maFonction)
print(info.name)       --> "maFonction"
print(info.what)       --> "Lua"
print(info.nparams)    --> 0
print(info.isvararg)   --> false

-- debug.getlocal : inspecter les variables locales
local x = 42
local nom = "test"
print(debug.getlocal(1, 1))  --> "x"  42
print(debug.getlocal(1, 2))  --> "nom"  "test"

assert amélioré

La fonction assert génère de meilleurs messages d'erreur en Lua 5.5.

-- assert avec message personnalisé
local function diviser(a, b)
    assert(b ~= 0, string.format("Division par zéro : %d / %d", a, b))
    return a / b
end

local ok, err = pcall(diviser, 10, 0)
print(err)  --> "main.lua:2: Division par zéro : 10 / 0"

-- assert peut valider les types et les structures
local function creerUtilisateur(nom, age)
    assert(type(nom) == "string", "nom doit être une chaîne")
    assert(type(age) == "number" and age > 0, "age doit être positif")
    return {nom = nom, age = age}
end

Gestion d'erreurs avec to-be-closed

-- Combinaison pcall + to-be-closed pour une gestion robuste
local function lireConfig(chemin)
    local config = {}
    do
        local <close> f = io.open(chemin, "r")
        if not f then
            return nil, "Fichier non trouvé : " .. chemin
        end
        for ligne in f:lines() do
            local cle, valeur = string.match(ligne, "^(%w+)%s*=%s*(.+)$")
            if cle then
                config[cle] = valeur
            end
        end
    end
    return config
end

local cfg, err = lireConfig("config.ini")
if not cfg then
    print("Erreur : " .. err)
end

Récapitulatif

  • pcall capture les erreurs, xpcall permet un traitement personnalisé.
  • debug.traceback fournit une pile d'appels complète.
  • La bibliothèque debug offre getinfo, getlocal pour l'inspection.
  • assert génère de meilleurs messages d'erreur en Lua 5.5.
  • Combiner pcall avec <close> pour une gestion d'erreurs robuste.

8. Les générateurs et itérateurs

Les générateurs et itérateurs sont des patterns puissants en Lua 5.5, combinant coroutines et fonctions pour créer des flux de données paresseux et efficaces.

Créer un générateur avec coroutine

Un générateur est une coroutine qui produit une séquence de valeurs via coroutine.yield.

-- Générateur de nombres premiers
local function premiers(max)
    return coroutine.create(function()
        for n = 2, max do
            local estPremier = true
            for i = 2, math.floor(math.sqrt(n)) do
                if n % i == 0 then
                    estPremier = false
                    break
                end
            end
            if estPremier then
                coroutine.yield(n)
            end
        end
    end)
end

-- Utilisation
local gen = premiers(30)
while coroutine.status(gen) ~= "dead" do
    local ok, p = coroutine.resume(gen)
    if ok and p then print(p) end
end
-- 2, 3, 5, 7, 11, 13, 17, 19, 23, 29

Le protocole d'itérateur en Lua 5.5

Un itérateur en Lua suit le protocole : une fonction qui retourne la valeur suivante, ou nil quand c'est fini.

-- Itérateur simple : parcourir les mots d'une chaîne
local function lireMots(texte)
    local pos = 1
    return function()
        local debut, fin = string.find(texte, "%w+", pos)
        if debut then
            pos = fin + 1
            return string.sub(texte, debut, fin)
        end
    end
end

for mot in lireMots("Bonjour le monde de Lua 5.5") do
    print(mot)
end

Itérateurs à état avec coroutine.wrap

coroutine.wrap retourne une fonction appelable directement, idéal pour les itérateurs à état complexe.

-- Itérateur de lignes CSV avec gestion des guillemets
local function lireCSV(contenu)
    return coroutine.wrap(function()
        for ligne in contenu:gmatch("[^\n]+") do
            local champs = {}
            for champ in ligne:gmatch("[^,]+") do
                table.insert(champs, champ)
            end
            coroutine.yield(champs)
        end
    end)
end

local csv = "nom,age,ville\nAlice,30,Paris\nBob,25,Lyon"
for ligne in lireCSV(csv) do
    print(table.concat(ligne, " | "))
end
-- nom | age | ville
-- Alice | 30 | Paris
-- Bob | 25 | Lyon

Itérateur de transformation (map/filter)

-- map : transformer chaque élément
local function map(iterateur, fn)
    return function()
        local val = iterateur()
        if val then return fn(val) end
    end
end

-- filter : ne garder que les éléments qui passent le test
local function filter(iterateur, test)
    return function()
        while true do
            local val = iterateur()
            if not val then return nil end
            if test(val) then return val end
        end
    end
end

-- Pipeline fonctionnel
local nombres = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local iter = ipairs(nombres)
local pairs = filter(function(i, v) return v % 2 == 0 end)
-- Utilisation simplifiée

Performance des itérateurs

-- Les closures sont plus rapides en Lua 5.5
-- Évitez les coroutines pour les itérateurs simples

-- Rapide : closure
local function compter(n)
    local i = 0
    return function()
        i = i + 1
        if i <= n then return i end
    end
end

-- Plus lent : coroutine (utilisez pour la complexité)
local function compterCoro(n)
    return coroutine.wrap(function()
        for i = 1, n do
            coroutine.yield(i)
        end
    end)
end

Récapitulatif

  • Les générateurs utilisent les coroutines pour produire des séquences paresseuses.
  • Le protocole d'itérateur : fonction retournant la valeur suivante ou nil.
  • coroutine.wrap crée des itérateurs appelables directement.
  • Les closures sont plus rapides que les coroutines pour les cas simples.
  • Les patterns map/filter permettent des pipelines fonctionnels.

9. Interopérabilité et API

L'interopérabilité avec le code C est l'un des points forts de Lua. Lua 5.5 apporte des changements à l'API C pour mieux gérer les userdata et les valeurs utilisateur.

L'API C de Lua 5.5

L'API C permet d'étendre Lua en intégrant des fonctions et des types écrits en C. Lua 5.5 introduit de légères modifications pour plus de sécurité.

/* Exemple d'extension C pour Lua 5.5 */
/* Créer un module C qui ajoute une fonction mathématique */

#include "lua.h"
#include "lauxlib.h"

/* Fonction C appelable depuis Lua */
static int l_factorielle(lua_State *L) {
    int n = luaL_checkinteger(L, 1);
    long result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    lua_pushinteger(L, result);
    return 1;
}

Userdata en Lua 5.5

Les userdata sont des blocs de mémoire brute gérés par Lua, utilisés pour intégrer des données C. Lua 5.5 améliore leur gestion avec lua_setiuservalue et lua_getiuservalue.

/* En Lua 5.5, lua_setuservalue/lua_getuservalue
   sont remplacés par : */
lua_setiuservalue(L, idx, utype);
lua_getiuservalue(L, idx, utype);

/* Les userdata ont maintenant un type numérique
   pour distinguer différents kinds */
static int l_creer_connexion(lua_State *L) {
    void *ud = lua_newuserdatauv(L, sizeof(Connexion), 1);
    luaL_setmetatable(L, "Connexion");
    return 1;
}

Embedding Lua 5.5

Intégrer Lua 5.5 dans une application C est similaire aux versions précédentes, avec quelques améliorations.

/* Programme hôte C avec Lua 5.5 */
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    /* Charger et exécuter un script Lua */
    if (luaL_dofile(L, "script.lua") != LUA_OK) {
        fprintf(stderr, "Erreur : %s\n", lua_tostring(L, -1));
    }

    /* Appeler une fonction Lua depuis C */
    lua_getglobal(L, "maFonction");
    lua_pushinteger(L, 42);
    if (lua_pcall(L, 1, 1, 0) == LUA_OK) {
        int resultat = lua_tointeger(L, -1);
        printf("Résultat : %d\n", resultat);
    }

    lua_close(L);
    return 0;
}

Les métaméthodes pour les userdata

-- Côté Lua : définir les métaméthodes pour un userdata C
local Point = {}

function Point.__add(a, b)
    return creerPoint(a.x + b.x, a.y + b.y)
end

function Point.__tostring(p)
    return string.format("Point(%d, %d)", p.x, p.y)
end

function Point.__eq(a, b)
    return a.x == b.x and a.y == b.y
end

-- Enregistrer la métatable pour un type userdata
luaL_newmetatable(L, "Point")

-- En Lua 5.5, les userdata supportent mieux
-- les uservalue multiples via lua_newuserdatauv

FFI et extensions

Bien que Lua 5.5 n'inclue pas de FFI natif, des bibliothèques comme LuaJIT's FFI ou les extensions C continuent d'être les moyens principaux d'interopérabilité.

-- Charger une bibliothèque C partagée
local socket = require("socket")

-- Utiliser des fonctions C depuis Lua
local tcp = socket.tcp()
tcp:connect("example.com", 80)
tcp:send("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
local response = tcp:receive("*a")
tcp:close()

-- Les bibliothèques C sont transparentes pour l'utilisateur Lua
-- Le même code fonctionne en Lua 5.4 et 5.5

Changements API Lua 5.5

  • lua_newuserdatauv remplace lua_newuserdata avec support des uservalue multiples.
  • lua_setiuservalue/lua_getiuservalue remplacent lua_setuservalue/lua_getuservalue.
  • Meilleure gestion de la rétrocompatibilité avec les modules existants.

Récapitulatif

  • L'API C de Lua 5.5 est largement compatible avec 5.4.
  • Les userdata bénéficient de lua_newuserdatauv et uservalue multiples.
  • L'embedding suit le même pattern : luaL_newstate, luaL_openlibs, luaL_dofile.
  • Les métaméthodes s'appliquent aux userdata pour un comportement Lua natif.
  • Les extensions C (sockets, JSON, etc.) restent les mêmes.

10. Performance et optimisation

Lua 5.5 introduit plusieurs améliorations de performance au niveau du VM, de la collecte de ordures et de la création de tables.

Optimisations du VM

Le VM (Machine Virtuelle) de Lua 5.5 a été optimisé pour réduire le nombre d'opérations courantes.

-- Les boucles numeriques sont plus rapides
-- Lua 5.5 optimise les opérations entières

-- Boucle intensive (mesurez avec os.clock)
local debut = os.clock()
local somme = 0
for i = 1, 10000000 do
    somme = somme + i
end
local fin = os.clock()
print(string.format("Temps : %.3fs", fin - debut))

Gestion de la mémoire et garbage collector

Le GC (garbage collector) de Lua 5.5 est plus efficace, avec de meilleurs heuristiques pour le nettoyage incrémental.

-- Configurer le garbage collector
collectgarbage("setpause", 100)   -- pause entre les cycles (en %)
collectgarbage("setstepmul", 200)  -- taille du pas (en %)

-- Forcer un cycle de GC
collectgarbage("collect")

-- Mesurer l'utilisation mémoire
print(collectgarbage("count"))  --> Ko utilisés

-- En Lua 5.5, le GC generational est amélioré
collectgarbage("generational", 20, 10)  -- mode generational

Création de tables optimisée

Lua 5.5 optimise la création de tables, notamment les tableaux de taille connue à l'avance.

-- Pré-allouer la taille d'un tableau
local taille = 10000
local t = table.create(taille, 0)  -- si disponible en 5.5

-- Alternative : table.pack pour les retours multiples
local resultats = table.pack(maFonction())

-- Éviter les tables temporaires dans les boucles
-- Mauvais : crée une nouvelle table à chaque itération
for i = 1, 1000 do
    local temp = {x = i, y = i * 2}  -- allocation à chaque tour
end

-- Meilleur : réutiliser une table
local temp = {}
for i = 1, 1000 do
    temp.x = i
    temp.y = i * 2
end

Strings et interning

Les chaînes en Lua sont internées (partagées en mémoire). Lua 5.5 optimise davantage ce mécanisme.

-- Les chaînes identiques partagent la même référence
local a = "bonjour"
local b = "bonjour"
print(a == b)          --> true
print(tostring(a) == tostring(b))  --> true

-- Éviter la création de chaînes inutiles dans les boucles
-- Mauvais : concaténation crée des chaînes temporaires
local resultat = ""
for i = 1, 1000 do
    resultat = resultat .. tostring(i) .. ","
end

-- Meilleur : utiliser table.concat
local parties = {}
for i = 1, 1000 do
    parties[i] = tostring(i)
end
local resultat = table.concat(parties, ",")

Bytecode et chargement

Lua 5.5 peut charger du bytecode pré-compilé pour un démarrage plus rapide.

-- Pré-compiler un fichier Lua en bytecode
-- luac -o mon_module.luac mon_module.lua

-- Charger le bytecode pré-compilé
local monModule = loadfile("mon_module.luac")()
-- Plus rapide que loadfile("mon_module.lua")

-- string.dump pour sérialiser une fonction en bytecode
local function maFonction() return 42 end
local bytecode = string.dump(maFonction)
print(#bytecode)  -- taille du bytecode en octets

-- Recharger depuis le bytecode
local recharge = load(bytecode)
print(recharge())  --> 42

Conseils d'optimisation

  • Mesurez toujours avec os.clock() avant d'optimiser.
  • Utilisez local partout — les accès locaux sont plus rapides.
  • Préférez table.concat à la concaténation avec ...
  • Évitez les tables temporaires dans les boucles chaudes.
  • Utilisez le bytecode pré-compilé pour les modules fréquemment chargés.

Récapitulatif

  • Le VM de Lua 5.5 est optimisé pour les opérations entières courantes.
  • Le garbage collector generational est amélioré.
  • La création de tables peut être optimisée en pré-allouant.
  • Les chaînes sont automatiquement internées.
  • Le bytecode pré-compilé accélère le chargement des modules.

11. Patterns et expressions régulières

Lua n'a pas d'expressions régulières au sens classique, mais offre un système de patterns (motifs) puissant et performant pour la recherche et la manipulation de chaînes.

Les fonctions de pattern matching

Les patterns Lua utilisent des séquences de caractères spéciaux pour décrire des motifs de recherche.

-- Les classes de caractères
-- %a : lettre, %d : chiffre, %w : alphanumérique
-- %s : espace blanc, %l : minuscule, %u : majuscule

local texte = "Contact : alice@example.com ou bob@site.org"

-- string.find avec pattern
local debut, fin = string.find(texte, "%a+@%a+%.%a+")
print(debut, fin)  --> 11  25
print(string.sub(texte, debut, fin))  --> alice@example.com

-- Les quantificateurs
-- + : un ou plusieurs, * : zéro ou plusieurs
-- - : zéro ou plusieurs (non-gourmand), ? : zéro ou un

print(string.match("abc123def456", "%d+"))  --> 123
print(string.match("abc123def456", "%d+.-"))  --> 123 (non-gourmand)

Les captures (captures)

Les parenthèses dans les patterns créent des captures qui extraient des parties de la chaîne correspondante.

-- Captures simples avec parenthèses
local date = "22/07/2026"
local jour, mois, annee = string.match(date, "(%d+)/(%d+)/(%d+)")
print(jour, mois, annee)  --> 22  07  2026

-- Capture avec spécificateur de classe
local tel = "Tél : 06 12 34 56 78"
local numero = string.match(tel, "(%d%d%s?%d%d%s?%d%d%s?%d%d%s?%d%d)")
print(numero)  --> "06 12 34 56 78"

Patterns avancés et captures nommées

-- Les motifs spéciaux
-- ^ : début de chaîne, $ : fin de chaîne
-- [] : ensemble, [^] : complément

-- Valider une adresse email
local function validerEmail(email)
    return string.match(email,
        "^[%w%.%%%+%-]+@[%w%.%-]+%.[%a]+$") ~= nil
end

print(validerEmail("alice@exemple.com"))  --> true
print(validerEmail("pas-un-email"))       --> false

-- Captures nommées avec balises
local url = "https://www.exemple.com/page?id=42"
local scheme, host, path, params = string.match(url,
    "^(%a[%w%+%-]*):/?/?([^/]+)(/?[^?]*)[?]?(.*)")
print(scheme, host, path, params)
--> https  www.exemple.com  /page  id=42

gmatch et gsub avancés

-- string.gmatch : itérer sur toutes les occurrences
local texte = "Les chats et les chiens sont gentils"
for mot in texte:gmatch("%a+") do
    print(mot)
end

-- gsub avec captures et fonctions
local texte2 = "Prix : 100 EUR, 200 EUR, 50 USD"

-- Remplacement avec fonction de transformation
local resultat = string.gsub(texte2, "(%d+)(%s?%a+)",
    function(montant, devise)
        return tonumber(montant) * 1.1 .. devise
    end)
print(resultat)
--> "Prix : 110 EUR, 220 EUR, 55 USD"

-- gsub avec motif de remplacement
local n = select(2, string.gsub(texte, "%a+", "X"))
print(string.format("%d mots trouvés", n))

Patterns communs prêts à l'emploi

-- Extraction de nombres
local donnees = "Température: 23.5°C, Humidité: 65%"
for nb in donnees:gmatch("%d+%.?%d*") do
    print(nb)
end

-- Validation de mot de passe
local function motDePasseFort(mdp)
    if #mdp < 8 then return false, "Trop court" end
    if not string.match(mdp, "%u") then return false, "Pas de majuscule" end
    if not string.match(mdp, "%l") then return false, "Pas de minuscule" end
    if not string.match(mdp, "%d") then return false, "Pas de chiffre" end
    return true
end

print(motDePasseFort("abc123"))   --> false  "Trop court"
print(motDePasseFort("Abc12345")) --> true

Récapitulatif

  • Lua utilise des patterns (pas des regex complètes) pour la recherche de texte.
  • string.find, string.match, string.gmatch, string.gsub sont les fonctions principales.
  • Les parenthèses créent des captures dans les patterns.
  • Les classes de caractères : %a, %d, %w, %s, etc.
  • gsub accepte des fonctions de transformation pour des remplacements complexes.

12. Projet final

Maintenant que vous maîtrisez Lua 5.5, il est temps de créer un projet complet ! Nous allons construire un pipeline de traitement de fichiers utilisant toutes les nouveautés de Lua 5.5 : <close> pour la gestion des fichiers, <const> pour la configuration, les coroutines pour le streaming, les patterns pour l'analyse, et la gestion d'erreurs robuste.

Ce que vous devez implémenter

  • <const> pour les constantes de configuration et les options.
  • <close> pour la fermeture automatique des fichiers et connexions.
  • Coroutines pour le streaming de données et les itérateurs.
  • Patterns pour l'analyse et la validation des données.
  • pcall/xpcall pour la gestion d'erreurs robuste.

Le module de configuration (config.lua)

-- config.lua : Configuration avec <const>
local Config = {}

-- Constantes de configuration
local <const> CHEMIN_ENTREE = "./data/entree.csv"
local <const> CHEMIN_SORTIE = "./data/sortie.json"
local <const> TAILLE_LOT = 100
local <const> VERSION = "1.0.0"

-- Patterns de validation
local <const> PATTERNS = {
    email = "^[%w%.%+%-]+@[%w%.%-]+%.[%a]+$",
    telephone = "^0[1-9]%d{8}$",
    date = "^%d%d%d%d%-%d%d%-%d%d$",
    nombre = "^-?%d+%.?%d*$",
}

Config.CHEMIN_ENTREE = CHEMIN_ENTREE
Config.CHEMIN_SORTIE = CHEMIN_SORTIE
Config.TAILLE_LOT = TAILLE_LOT
Config.VERSION = VERSION
Config.PATTERNS = PATTERNS

return Config

Le module de traitement (processeur.lua)

-- processeur.lua : Pipeline de traitement avec coroutines
local Config = require("config")

local Processeur = {}

-- Générateur de lignes CSV avec coroutine
function Processeur.genererLignes(cheminFichier)
    return coroutine.create(function()
        do
            local <close> f = io.open(cheminFichier, "r")
            if not f then
                error("Fichier non trouvé : " .. cheminFichier)
            end

            local enTete = nil
            for ligne in f:lines() do
                if enTete == nil then
                    enTete = ligne
                else
                    coroutine.yield(ligne, enTete)
                end
            end
        end
    end)
end

-- Parser une ligne CSV
function Processeur.parserCSV(ligne, enTete)
    local champs = {}
    local i = 1
    for valeur in ligne:gmatch("[^,]+") do
        local nom = select(2, string.match(enTete, "([^,]+)", 1))
        champs[i] = string.trim(valeur)
        i = i + 1
    end
    return champs
end

-- Valider les données avec les patterns
function Processeur.valider(donnees)
    local erreurs = {}
    if donnees.email and not string.match(donnees.email, Config.PATTERNS.email) then
        table.insert(erreurs, "Email invalide : " .. donnees.email)
    end
    if donnees.telephone and not string.match(donnees.telephone, Config.PATTERNS.telephone) then
        table.insert(erreurs, "Téléphone invalide : " .. donnees.telephone)
    end
    if donnees.date and not string.match(donnees.date, Config.PATTERNS.date) then
        table.insert(erreurs, "Date invalide : " .. donnees.date)
    end
    return #erreurs == 0, erreurs
end

-- Transformer les données
function Processeur.transformer(ligne)
    return {
        nom = string.upper(ligne.nom),
        email = string.lower(ligne.email),
        age = tonumber(ligne.age) or 0,
        date_inscription = ligne.date,
    }
end

return Processeur

Le programme principal (main.lua)

-- main.lua : Pipeline de traitement de fichiers Lua 5.5
local Config = require("config")
local Processeur = require("processeur")

print("========================================")
print("  PIPELINE DE TRAITEMENT LUA " .. Config.VERSION)
print("========================================")

-- Statistiques avec <const>
local <const> stats = {
    traites = 0,
    erreurs = 0,
    ignores = 0,
}

-- Pipeline principal avec gestion d'erreurs
do
    local ok, err = pcall(function()
        -- Lancer le générateur de lignes
        local gen = Processeur.genererLignes(Config.CHEMIN_ENTREE)

        -- Ouvrir le fichier de sortie
        local <close> sortie = io.open(Config.CHEMIN_SORTIE, "w")
        if not sortie then
            error("Impossible de créer le fichier de sortie")
        end

        sortie:write("[\n")
        local premier = true

        -- Parcourir le générateur
        while coroutine.status(gen) ~= "dead" do
            local okLigne, ligne, enTete = coroutine.resume(gen)

            if okLigne and ligne then
                local donnees = Processeur.parserCSV(ligne, enTete)

                -- Valider
                local valide, errs = Processeur.valider(donnees)
                if valide then
                    -- Transformer
                    local transforms = Processeur.transformer(donnees)
                    stats.traites = stats.traites + 1

                    -- Écrire en JSON
                    if not premier then sortie:write(",\n") end
                    premier = false
                    sortie:write("  {")
                    sortie:write('"nom": "' .. transforms.nom .. '", ')
                    sortie:write('"email": "' .. transforms.email .. '", ')
                    sortie:write('"age": ' .. transforms.age)
                    sortie:write("}")
                else
                    stats.erreurs = stats.erreurs + 1
                    print("[ERREUR] " .. table.concat(errs, "; "))
                end
            end
        end

        sortie:write("\n]\n")
        print("Fichier de sortie créé : " .. Config.CHEMIN_SORTIE)
    end)

    if not ok then
        print("[FATAL] " .. err)
    end
end

-- Afficher les statistiques
print("\n--- Statistiques ---")
print("Traités : " .. stats.traites)
print("Erreurs : " .. stats.erreurs)
print("Ignorés : " .. stats.ignores)
print("Terminé !")

Les patterns pour l'analyse avancée

-- utils.lua : Fonctions utilitaires avancées avec patterns
local Utils = {}

-- Extraire toutes les URLs d'un texte
function Utils.extraireURLs(texte)
    local urls = {}
    for url in texte:gmatch("https?://[%w%.%-]+[%w%.%-/]*[%?%w=&%-]*") do
        table.insert(urls, url)
    end
    return urls
end

-- Formater un nombre avec séparateurs de milliers
function Utils.formaterNombre(nb)
    local texte = tostring(nb)
    local resultat = texte:reverse():gsub("(%d%d%d)", "%1."):reverse()
    if resultat:sub(1, 1) == "." then
        resultat = resultat:sub(2)
    end
    return resultat
end

-- Masquer partiellement une adresse email
function Utils.maskerEmail(email)
    return string.gsub(email, "(%w)([%w%.%-]*@)",
        function(premier, reste)
            return premier .. string.rep("*", #reste - 1) .. "@"
        end)
end

return Utils

Conseils pour réussir

  • Commencez par le module de configuration avec <const>.
  • Implémentez le processeur de données avec les coroutines.
  • Testez chaque module individuellement avec lua -i.
  • Utilisez <close> pour toutes les ressources (fichiers, connexions).
  • Ajoutez la gestion d'erreurs avec pcall et xpcall.
  • Expérimentez : ajoutez du filtrage, du tri, des rapports.
  • Utilisez les patterns pour valider et transformer les données.
  • Mesurez les performances avec os.clock().

Récapitulatif du cours

  • <const> : constantes et configuration sûre.
  • <close> : nettoyage automatique des ressources.
  • Coroutines : générateurs et streaming de données.
  • Patterns : analyse et validation de texte puissante.
  • pcall/xpcall : gestion d'erreurs robuste.
  • Vous êtes maintenant prêt à utiliser Lua 5.5 dans vos projets !

Bienvenue