Lua变量范围与setfenv

SJM*_*JML 5 lua scope sandbox

我正在尝试使用原始Lua文件进行配置,但不希望配置文件污染全局命名空间.

我遇到的问题dofile似乎总是在真实的全局环境中执行,因此外部文件只是将所有声明都抛入_G.

这是一个示例主文件,注释表明我的一厢情愿.

function myFunc()
    print("In the sandbox:")
    print("Should be 1:", a)  -- falls back to _G for lookup
    a = 2  -- instantiating new global for sandbox
    print("Should be 2:", a)  -- from sandbox
    print("Should still be 1:", _G.a)  -- from host environment

    dofile("loading.lua")  -- here's where things go wrong

    print "\nBack in the sandbox:"
    print("Should be 3:", a)  -- changed by loadfile
    print("Should STILL be 1:", _G.a)  -- unchanged
end

a = 1
local newgt = {} -- new environment
setmetatable(newgt, {__index = _G})
setfenv(myFunc, newgt)
myFunc()

print("\nOutside of the sandbox:")
print("Should be 1: ", a)  -- in theory, has never changed
Run Code Online (Sandbox Code Playgroud)

它正在加载的文件(loading.lua:

print ("\nLoading file...")

print("Should be 2: ", a) -- coming from the sandbox environment
a = 3
print("Should be 3: ", a) -- made a change to the environment
Run Code Online (Sandbox Code Playgroud)

最后我看到的输出:

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
Run Code Online (Sandbox Code Playgroud)

gwe*_*ell 10

您描述的问题也在此页面上讨论Dofile Namespace Proposal.解决方案似乎是以下替代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
Run Code Online (Sandbox Code Playgroud)

另请参见:沙盒

  • 谢谢你的链接.要封装与该问题相关的页面学习:`dofile`**always**在全局命名空间中操作,忽略其调用函数的环境.尝试用`setfenv`直接影响它会引发错误.同样的限制不适用于从`loadfile`返回的匿名编译函数,所以使用上面的代码,你可以解决这个限制. (2认同)