Таблица Luf 5.1 setfenv() все еще загружается в глобальном пространстве

Я пытался работать с 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()" загружает таблицу в глобальное пространство, хотя я установил среду "песочницы" в "scriptTable", используя "setfenv (sandbox, scriptTable)" до выполнения "sandbox()".

Я прошел Пример Песочницы, упомянутый в других постах, но я все еще получаю те же результаты. Любая идея, что я могу сделать, чтобы загрузить сценарий в его собственной среде, не загрязняя глобальную среду?

1 ответ

Решение

Вы на самом деле не загрязняете глобальную среду, вы видите здесь природу системы пакетов, что модули кэшируются и совместно используются для каждого вызова require, не зависящий от среды вызывающей функции. Это позволяет модулю Singleton работать, потому что если вы не будете require это, но сделать loadfile, он будет загружен дважды (и будет меньше, чем ожидалось).

Таким образом, если реальная задача состоит в том, чтобы загрузить модуль только один раз для песочницы, то вы можете поменять местами package.loaded, package.preload и другие переменные состояния загрузчика перед входом в песочницу. Больше информации в Modules раздел Lua 5.1 Справочное руководство.

Решение с loadfile Это может быть просто замечательно, но если вы планируете перекрестно требовать модули в сложной модульной системе внутри вашей песочницы, это действительно приведет к большой проблеме.

Другие вопросы по тегам