2010-06-23 11 views
5

J'essaie d'utiliser des fichiers Lua bruts à des fins de configuration, mais je ne veux pas que les fichiers de configuration polluent l'espace de noms global.Lua variable portée avec setfenv

Le problème que je rencontre est que dofile semble toujours s'exécuter dans l'environnement global réel, donc les fichiers externes jettent toutes leurs déclarations dans _G.

Voici un exemple de fichier principal, avec des commentaires indiquant mes vœux pieux.

function myFunc() 
    print("In the sandbox:") 
    print("Should be 1:", a) -- falls back to _G for lookup 
    a = 2 -- instantiating new global for sandbox 
    print("Should be 2:", a) -- from sandbox 
    print("Should still be 1:", _G.a) -- from host environment 

    dofile("loading.lua") -- here's where things go wrong 

    print "\nBack in the sandbox:" 
    print("Should be 3:", a) -- changed by loadfile 
    print("Should STILL be 1:", _G.a) -- unchanged 
end 

a = 1 
local newgt = {} -- new environment 
setmetatable(newgt, {__index = _G}) 
setfenv(myFunc, newgt) 
myFunc() 

print("\nOutside of the sandbox:") 
print("Should be 1: ", a) -- in theory, has never changed 

Et le fichier son chargement (loading.lua:

print ("\nLoading file...") 

print("Should be 2: ", a) -- coming from the sandbox environment 
a = 3 
print("Should be 3: ", a) -- made a change to the environment 

Et enfin la sortie que je vois:

In the sandbox: 
Should be 1: 1 
Should be 2: 2 
Should still be 1: 1 

Loading file... 
Should be 2: 1 
Should be 3: 3 

Back in the sandbox: 
Should be 3: 2 
Should STILL be 1: 3 

Outside of the sandbox: 
Should be 1: 3 
+2

Vous imprimez le 1 littéral au lieu de la valeur pour un. Si c'est un travail de copier-coller, alors votre code est faux, ce qui explique pourquoi vous voyez cette dernière ligne affligeante. –

+0

Ha! Merci, le gros-doigté est le coupable d'au moins la fin. Merci pour la capture. – SJML

Répondre

10

Le problème que vous décrivez est également discuté sur cette page Dofile Namespace Proposal. La solution a semblé être le remplacement suivant pour dofile:

function myapp.import(name) 
    local f,e = loadfile(name) 
    if not f then error(e, 2) end 
    setfenv(f, getfenv(2)) 
    return f() 
end 

Voir aussi: Sand Boxes

+2

Merci pour le lien. Pour encapsuler les apprentissages de cette page qui sont pertinents à cette question: 'dofile' ** always ** opère dans l'espace de noms global, en ignorant l'environnement de sa fonction d'appel. Tente de l'affecter directement avec 'setfenv' génère une erreur. Cette même restriction ne s'applique pas à une fonction compilée anonyme renvoyée par 'loadfile', donc en utilisant le code ci-dessus, vous contournez cette limitation. – SJML

+1

@SJML, exactement. Ma compréhension est que 'dofile' est un peu comme le stock' print'. Il est là pour sa grande commodité pour le novice et l'apprenant, surtout à l'invite interactive. Un code sérieux éviterait la fonction ou la redéfinirait pour travailler en toute sécurité dans le monde réel. – RBerteig