Lua变量作用域与setfenv函数

我试着使用原始的 Lua 文件作为配置文件,但不想让配置文件污染全局命名空间。

我遇到的问题是dofile似乎总是在真正的全局环境中执行,所以外部文件会将它们的所有声明都扔到 _G中。

下面是一个示例主文件,注释说明了我的愿望。

function myFunc()
    print("In the sandbox:")
    print("Should be 1:", a)  -- 在查找时退回到_G
    a = 2  -- 为sandbox实例化新的全局环境
    print("Should be 2:", a)  -- 来自sandbox
    print("Should still be 1:", _G.a)  -- 来自主机环境

    dofile("loading.lua")  -- 这是出错的地方

    print "\nBack in the sandbox:"
    print("Should be 3:", a)  -- 被loadfile改变
    print("Should STILL be 1:", _G.a)  -- 未改变
end

a = 1
local newgt = {} -- 新环境
setmetatable(newgt, {__index = _G})
setfenv(myFunc, newgt)
myFunc()

print("\nOutside of the sandbox:")
print("Should be 1: ", a)  -- 理论上,它从未更改过

以及它所加载的文件(loading.lua):

print ("\nLoading file...")

print("Should be 2: ", a) -- 来自sandbox环境
a = 3
print("Should be 3: ", a) -- 更改了环境

最后是我看到的输出:

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

原文链接 https://stackoverflow.com/questions/3098544

点赞
stackoverflow用户173806
stackoverflow用户173806

你描述的问题也在这个网页上文件命名空间提议上讨论过。 解决方案似乎是以下替换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

另请参阅:沙盒

2010-06-23 05:54:16