Lua 5.1 setfenv()表仍然在全局空间中加载

时间:2014-02-12 18:16:56

标签: lua env lua-5.1 lua-loadfile

我一直在尝试使用setfenv()来将一个块加载到全局环境之外的环境中,但是我遇到了一些麻烦。以下是我正在运行的代码:

-- main.lua
function SandboxScript(scriptTable, scriptName)
    setmetatable(scriptTable, { __index = _G })
    local sandbox = loadfile(scriptName)
    setfenv(sandbox, scriptTable)
    sandbox()
    return scriptTable
end

local function main()
    print(Singleton)
    local test = {}
    local single1 = SandboxScript(test, "C:\\pathto\\TestTable.lua")
    print(Singleton)
    test.Update()

    local test2 = {}
    local single2 = SandboxScript(test2, "C:\\pathto\\TestTable.lua")
    test2.Update()
end
main()

-- TestTable.lua
require("Singleton")
local test = {}

function Update()
    test = Singleton:new()
    print(test.var)
    test.var = "Changed"
    print(test.var)
end

-- Singleton.lua
Singleton = {}
Instance = {}

function Singleton:new()
    if(next(Instance)) then
        return Instance
    end

    Instance.var = "Init"
    return Instance
end

我期待这个的输出是:

nil      --(First check in global table before running sandbox code)
nil      --(Second check in global table after running sandbox code)
Init     --(Initial value of the Singleton's var)
Changed  --(Singleton's var after we change it)
Init     --(Initial value of the Singleton's var in a different sandbox)
Changed  --(Singleton's var after we change it in the different sandbox)


相反,我得到了:

nil
table: 05143108
Init
Changed
Changed
Changed

指示“sandbox()”正在将表加载到全局空间中,即使我在执行“sandbox()”之前使用“setfenv(sandbox,scriptTable)”将沙盒的环境设置为“scriptTable”。

我已经浏览了其他帖子中提到的Sand Boxes Example,但我仍然得到了相同的结果。知道如何在不污染全球环境的情况下在自己的环境中加载脚本吗?

1 个答案:

答案 0 :(得分:1)

你并没有真正污染全球环境,你在这里看到的是包系统的本质,每次调用require时都会缓存和共享模块,而不依赖于调用函数的环境。这允许Singleton模块工作,因为如果你不require它,而是loadfile,它将加载两次(并且非常少于预期的单例)。

因此,如果真正的任务是只加载模块一次每个沙箱 ,那么您可以交换package.loadedpackage.preload和其他加载器进入沙箱之前的状态变量。有关Lua 5.1参考手册的Modules部分的更多信息。

使用loadfile的解决方案可能会很好,但是如果您计划在沙箱中的复杂模块系统中交叉需要模块,那么这将导致一个大问题。