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.