这不是完全可以实现的,因为修改 local 值(debug.setlocal 不能定义 new 局部变量)是不完美的。最好的办法是调整您的环境,因为污染全局范围不是一个好主意,但这并非不重要。
这实际上可以在某种程度上优雅地完成,如果仔细完成的话。我有点说,因为总会有一个警告,你必须为你所在的任何功能/块手动调整你的环境。在 Lua 5.2+ 中,local _ENV = ... 是必需的。在 Lua 5.1 中,setfenv(1, ...) 可以做到这一点,并且可以说更容易看。
这是我们可以做的。我们首先定义一个返回克隆环境的函数。 clone 是一个浅表复制函数。
return function (env)
env = clone(env or _G)
return env
end
接下来,我们添加自定义的import 函数,该函数直接修改我们的新环境,而不是返回任何内容(如require 所做的那样)。您可以在这里变得既好又复杂,实施不同的方法来决定将什么导入环境以及如何导入。 (例如'*')
-- @module: import.lua
return function (env)
env = clone(env or _G)
function env.import (modname, ...)
local args = { ... }
local m = require(modname)
for _, name in next, args
env[name] = m[name]
end
end
return env
end
我们可以用作:
local _ENV = require('import')()
-- setfenv(1, require('import')())
import('module_name', 'a', 'b')
return a + b
在小范围内,这是相当大的开销,只是为了避免:
local module_name = require('module_name')
local a, b = module_name.a, module_name.b
它可能在具有许多导入的较大文档中更有用。导入通常以任何方式聚集在文档的顶部,因此额外的噪音并不是那么糟糕。如果您可以在某处将env 设置为全局值,它看起来会更干净一些。
local _ENV = env()
import('webserver', 'open', 'status', 'close')
import('database', 'connect', 'query', 'disconnect')
import('json', 'parse', 'stringify')
...
并且还可以用于创建沙盒,前提是注意重写 import 函数以不使用 require!
local my_env = env { print = print }
my_env.import('my_mod', 'foo', 'bar')
local chunk = loadfile('my_file.lua', 'bt', my_env)