En règle générale, l'affectation est suffisante pour obtenir et définir les variables globales.
Mais la difficulté survient lorsque vous voulez manipuler une variable globale dont le nom est stocké dans une autre variable, ou lorsque vous voulez la calculer au moment de l'exécution.
Pour obtenir la valeur de cette variable, de nombreux programmeurs sont tentés d'écrire quelque chose comme:
loadstring("value = " .. varname)() ou bien value = loadstring("retour " .. varname)()
Si par exemple, varname a la valeur connue x, la concaténation se traduira par "retour x " (ou "value = x", avec la première forme).
Cependant, ces codes impliquent la création et la compilation d'un nouveau morceau de code et beaucoup de travail supplémentaire.
Vous pouvez accomplir la même chose avec le code suivant, beaucoup plus court et bien plus efficace que le précédent.
value = _G[varname]
Puisque l'environnement est une table ordinaire, vous pouvez simplement l'indexer avec le nom de la variable.
De la même manière, vous pouvez assigner directement une variable globale en écrivant:
_G[varname] = valeur.
Mais attention:
Certains programmeurs quelque peu excités par ces fonctions peuvent arriver à écrire:
_G["a"] = _G["var1"], qui est juste une manière compliquée d'écrire var1 = a
Une généralisation du problème précédent est de permettre d'accéder à tous les champs (mots, caractères...etc.) contenus dans un nom dynamique, comme "io.read" ou "a.b.c.d".
Vous résoudrez ce problème avec une boucle qui démarre à _G et évolue, champ par champ.
function Getfield(f) local v = _G -- début de la table _G for w in string.gmatch(f, "[%w_]+") do v = v[w] end return v end
La fonction string.gmatch(), de la bibliothèque string, itère tous les mots contenus dans f. (où "mots" est une séquence d'un ou plusieurs caractères alphanumériques et/ou de soulignement).
La fonction correspondante utilisée pour définir des champs est un peu plus complexe.
Une affectation comme a.b.c.d.e = v est équivalente à:
local temp = a.b.c.d temp.e = v
Autrement dit, pour récupérer le dernier nom, vous devez gérer le dernier champ séparément.
La fonction suivante Setfield() créer également des tables intermédiaires dans un chemin où elles n'existent pas.
function Setfield(f, v) local t = _G -- on démarre avec la table Globale for w, d in string.gmatch(f, "([%w_]+)(.?)") do if d == "." then -- pas le dernier champ? t[w] = t[w] or {} -- on créer une table si absente t = t[w] -- get the table else -- dernier champs t[w] = v -- on assigne end end end
Ce nouvel exemple capture le nom du champ dans la variable w et un point optionnel dans la variable d.
Si un nom de champ n'est pas suivi par un point, c'est qu'il est le dernier.
Avec la fonction précédente, l'appel à Setfield("t.x.y", 10) crée une table t globale, et une autre table t.x, et assigne 10 à t.x.y
print( t.x.y ) --> 10 print( Getfield( "t.x.y" ) ) --> 10