在不污染全球环境的情况下加载文件



如何在不污染全局环境的情况下加载lua表和变量的文件?因为做一个加载文件并运行它只是加载全局空间中的所有内容,可能会覆盖我不想要的其他内容。

在Lua 5.1中,在没有太多错误处理的情况下,您可以这样做:

-- load and run a script in the provided environment
-- returns the modified environment table
function run(scriptfile)
    local env = setmetatable({}, {__index=_G})
    assert(pcall(setfenv(assert(loadfile(scriptfile)), env)))
    setmetatable(env, nil)
    return env
end

第一行创建了一个空的环境表,它可以看到所有现有的全局变量,但不能简单地更改它们,因为它们只能通过__index元方法通过代理可见。脚本创建的任何全局变量都将存储在返回的env中。这将适用于只设置一组配置参数的简单脚本,并且可能需要调用简单的安全函数来根据运行时的条件进行设置。

请注意,使全局变量对脚本可见是一种方便。尽管全局变量不能以显而易见的方式从脚本中修改,但_G是一个全局变量,它包含对全局环境的引用(包含_G._G_G._G._G等),而_G可以从脚本中进行修改,这可能会导致进一步的问题。

因此,与其使用_G作为索引,不如构造一个只包含已知安全和脚本作者需要的函数的表。

一个完整的解决方案是在沙盒中运行脚本,并可能得到进一步的保护,以防止意外(或故意)拒绝服务或更糟的情况。沙盒在Lua用户的Wiki中有更详细的介绍。这个话题比乍一看更深入,但只要你的用户被信任为非恶意用户,那么实用的解决方案就很简单。

Lua 5.2通过删除setfenv()而将新参数改为load(),从而稍微改变了一些情况。详细信息也在wiki页面中。

这是RBerteig的答案的dofile()版本,您可以在其中提供环境并返回结果(如果有的话)(我试图将其作为注释进行操作,但无法确定其格式):

local function DofileIntoEnv(filename, env)
    setmetatable ( env, { __index = _G } )
    local status, result = assert(pcall(setfenv(assert(loadfile(filename)), env)))
    setmetatable(env, nil)
    return result
end

我希望能够将多个文件加载到同一个环境中,其中一些文件中有"返回内容"。谢谢RBerteig,你的回答很有帮助,很有启发性!

在Lua>5.2

function run_test_script(scriptfile)
    local env = setmetatable({}, {__index=_G})
    assert(pcall(loadfile(scriptfile,"run_test_script",env)))
    setmetatable(env, nil)
    return env
end

相关内容

  • 没有找到相关文章

最新更新