2010-06-23 22 views
5

Yapılandırma amacıyla ham Lua dosyalarını kullanmaya çalışıyorum, ancak genel ad alanını kirleten yapılandırma dosyalarını istemiyorum.Setfenv ile Lua değişken kapsam belirleme

Karşılaştığım sorun, her zaman gerçek küresel ortamda yürütüldüğü için dofile'un dış dosyalarının tüm bildirimlerini _G'ye atamasıdır.

İşte örnek bir ana dosya, istekleri olan düşüncelerimi gösteren yorumlar.

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 

Ve dosyası, yüklüyor (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 

Ve nihayet çıktı görüyorum:

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

Bunun yerine ilişkin değerin literal 1 yazdırıyorsunuz. Bu bir kesme & yapıştırma işi ise, kodunuz yanlıştır, bu yüzden bu üzücü son çizgiyi görüyorsunuz. –

+0

Ha! Teşekkürler, şişman parmak ucu en azından sonunda suçludur. Yakalama için teşekkürler. – SJML

cevap

10

açıkladığınız sorun da bu sayfada Dofile Namespace Proposal üzerinde tartışılmaktadır. Çözüm, dofile:

için aşağıdaki yedek gibi görünüyordu. 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 

Ayrıca bakınız: Sand Boxes

+2

Bağlantı için teşekkürler. Bu sayfadaki öğrenmeleri bu soruyla ilgili olarak kapsüllemek için: 'dofile' ** her zaman **, arama işlevinin ortamını göz ardı ederek, global ad alanında çalışır. 'Setfenv' ile doğrudan etkileme girişimleri bir hata oluşturur. Aynı kısıtlama, 'loadfile''dan döndürülen anonim bir derlenmiş işlev için geçerli değildir, bu nedenle yukarıdaki kodu kullanarak bu sınırlamayı aşabilirsiniz. – SJML

+1

@SJML, tam olarak. Benim anlayışım, 'dofile' stoğu 'print' gibi biraz. Özellikle interaktif bilgi isteminde acemi ve öğreniciye büyük kolaylık var. Ciddi kod, ya işlevden kaçınır ya da gerçek dünyada güvenli bir şekilde çalışmak için onu yeniden tanımlar. – RBerteig