2010-06-23 15 views
5

Ich versuche, rohe Lua-Dateien zu Konfigurationszwecken zu verwenden, aber die Konfigurationsdateien nicht den globalen Namespace zu belasten.Lua Variable Scoping mit Setfenv

Das Problem, das ich renne ist, dass dofile scheint immer in der realen globalen Umgebung auszuführen, so externe Dateien werfen Sie einfach alle ihre Deklarationen in _G.

Hier ist eine Beispiel-Hauptdatei, mit Kommentaren, die meine Wunschvorstellung angeben.

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 

Und die Datei es zu laden (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 

Und schließlich der Ausgang Ich sehe:

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

Sie drucken die wörtliche 1 anstelle des Wertes für a. Wenn dies ein Cut & Paste-Job ist, dann ist Ihr Code falsch, weshalb Sie diese erschreckende letzte Zeile sehen. –

+0

Ha! Danke, Fett-Fingersatz ist der Schuldige zumindest des Endes. Danke für den Fang. – SJML

Antwort

10

Das Problem, das Sie beschreiben auch auf dieser Seite Dofile Namespace Proposal diskutiert wird. Die Lösung schien der folgende Ersatz für dofile zu sein:

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

Siehe: Sand Boxes

+2

Danke für den Link. Um die für diese Frage relevanten Erkenntnisse von dieser Seite einzukapseln: 'dofile ** ** always ** operiert im globalen Namespace und ignoriert dabei die Umgebung seiner aufrufenden Funktion. Versuche, es direkt mit 'setfenv' zu beeinflussen, führen zu einem Fehler. Die gleiche Einschränkung gilt nicht für eine anonyme kompilierte Funktion, die von 'loadfile' zurückgegeben wird. Mit dem obigen Code umgehen Sie diese Einschränkung. – SJML

+1

@SJML, genau. Mein Verständnis ist, dass "dofile" ein bisschen wie der Stock 'print' ist. Es ist wegen seiner großen Bequemlichkeit für Anfänger und Lernende, besonders bei der interaktiven Aufforderung, da. Seriöser Code würde entweder die Funktion vermeiden oder sie neu definieren, um in der realen Welt sicher zu funktionieren. – RBerteig