【问题标题】:Lua 5.1 setfenv() table still loading in global spaceLua 5.1 setfenv() 表仍在全局空间中加载
【发布时间】:2014-03-11 06:28:39
【问题描述】:

我一直在尝试使用 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,但我仍然得到相同的结果。知道如何在不污染全局环境的情况下在自己的环境中加载脚本吗?

【问题讨论】:

  • 似乎require("Singleton") 在全球环境中执行Singleton.lua 尽管当前环境。
  • @egor-skriptunoff 你给了我一个想法。它并没有解决整个问题,但取得了一些进展。在 TestTable 中执行以下操作:local singletonTable = loadfile("C:\\pathto\\Singleton.lua") singletonTable() 导致以下输出:niltable: 051D3108InitChangedInitChanged 这似乎仍然将 Singleton 加载到全局环境中,但至少保留了实例这次在正确的环境中。

标签: lua env lua-5.1 lua-loadfile


【解决方案1】:

您并没有真正污染全局环境,您在这里看到的是包系统的本质,即每次调用require 时都会缓存和共享模块,而不取决于调用函数的环境。这允许 Singleton 模块工作,因为如果您不使用 require 它,而是使用 loadfile,它将加载两次(并且比预期的要少得多)。

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

loadfile 的解决方案可能还不错,但是如果您打算在沙箱内的复杂模块系统中交叉需求模块,这确实会导致一个大问题。

【讨论】:

  • 你是绝对正确的,阅读 Lua 文档我对 require 的工作方式不正确,事实证明,在幕后,出于所有意图和目的,require 只是 loadfile .我已将代码更改为使用 loadfile 并且一切正常。
猜你喜欢
  • 2012-12-26
  • 2018-03-04
  • 2016-07-21
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
相关资源
最近更新 更多