Variables et portée

Globales et locales

Une variable non déclarée avec local est globale : elle vit dans la table d'environnement partagée par tout le script (et visible depuis l'hôte via l'API du moteur).

x = 10          -- variable globale
local y = 20    -- variable locale au bloc courant

Une variable locale n'est visible qu'à partir de sa déclaration jusqu'à la fin du bloc englobant (do...end, corps de function, corps de boucle, etc.) :

do
    local a = 1
    print(a)    --> 1
end
print(a)        --> nil (a n'existe plus, donc lecture d'une globale absente)

Une déclaration locale peut masquer (« shadow ») une variable de même nom d'un bloc englobant ou une globale :

local x = 1
do
    local x = 2
    print(x)    --> 2
end
print(x)        --> 1

Déclaration locale

local a
local b = 1
local c, d = 1, 2
local e, f = 1          -- f vaut nil (pas assez de valeurs)
local g = 1, 2, 3       -- le 2 et le 3 sont évalués puis ignorés (pas assez de cibles)

local function f(...) ... end déclare f comme locale avant de compiler son corps, ce qui permet à la fonction de s'appeler elle-même récursivement :

local function fact(n)
    if n <= 1 then return 1 end
    return n * fact(n - 1)
end

Attributs de variable locale

La grammaire admet une syntaxe d'attribut sur une variable locale (local x <attrib> = ...). <const> et <close> sont reconnus ; tout autre nom lève une erreur de syntaxe (« Attribut '...' inconnu »). Un nom ne porte qu'un seul attribut à la fois (local x <const> <close> = ... n'est pas une syntaxe valide).

<const> interdit toute réaffectation de la variable après sa déclaration — une nouvelle affectation (x = ...) est un rejet à la compilation, pas une erreur d'exécution :

local x <const> = 42
print(x)       -- lecture, capture par une closure, etc. : aucune restriction
x = 43         --> erreur de compilation : tentative d'affectation à la variable constante 'x'

Une nouvelle déclaration local x = ... du même nom n'est pas une réaffectation (c'est une variable distincte qui masque la précédente, comme toujours en Lua) — donc valide même après local x <const> = ....

<close> déclare une variable à fermeture automatique (to-be-closed) : sa valeur doit être false, nil, ou posséder une métaméthode __close — sinon une erreur est levée immédiatement, à la déclaration. __close(valeur, erreur) est invoquée automatiquement quand la variable sort de portée (fin de bloc, retour de fonction, ou déroulement dû à une erreur — erreur vaut alors l'objet d'erreur qui se propage, sinon nil), dans l'ordre inverse de déclaration si plusieurs variables <close> coexistent dans le même bloc. Voir Métatables pour le détail de la métaméthode.

local function lire(nom)
    local f <close> = io.open(nom, "r")   -- f:close() automatiquement, même en cas d'erreur
    return f:read("a")
end

Affectation

x = 1
x, y = 1, 2
t.field, t[1] = "a", "b"

L'affectation multiple évalue d'abord toute la liste de valeurs à droite, puis affecte chaque cible dans l'ordre. S'il y a plus de cibles que de valeurs, les cibles en trop reçoivent nil ; s'il y a plus de valeurs que de cibles, les valeurs en trop sont évaluées (pour leurs effets de bord éventuels) puis ignorées.

Une fonction ou ... en dernière position d'une liste (valeurs d'affectation, arguments d'appel, éléments d'un constructeur de table, liste de return) développe toutes ses valeurs de retour ; ailleurs dans la liste, elle est réduite à sa première valeur uniquement :

local function two() return 1, 2 end

local a, b = two()          -- a=1, b=2
local c, d = two(), 10      -- c=1 (two() est tronqué), d=10
local t = { two(), two() }  -- t = {1, 1, 2}  (seul le dernier two() se développe)

Arguments variables (...)

Une fonction déclarée avec ... dans sa liste de paramètres (voir Fonctions) peut utiliser ... comme une expression dans son corps, avec les mêmes règles d'expansion :

local function sum(...)
    local total = 0
    for _, v in ipairs({ ... }) do
        total = total + v
    end
    return total
end

... n'est utilisable que dans le corps direct d'une fonction variadique — pas dans une fonction imbriquée non variadique. Le script lui-même est toujours variadique : ... est utilisable au niveau supérieur d'un script pour récupérer les arguments qui lui sont passés par l'hôte.