Require
原型
function require (name)
if not package.loaded[name] then
local loader = findloader(name)
if loader == nil then
error("unable to load module"..name)
end
package.loaded[name] = true
local res = loader(name)
if res ~= nil then
package.loaded[name] = res
end
end
return package.loaded[name]
end
可以看出来,如果一个模块已经加载过,将不会被再次加载。
顺序
1.package.loaded
2.package.path
3.package.loadlib
module
它将我们的模块表加入到全局变量中,那么模块的主程序块就有一个独占的环境,这样访问同一模块的其他公共实体时,不需要限定它名称。
module ("aModule")
-- 相当于
local name = "aModule" -- 定义模块名
local M = {} -- 定义用于返回的模块表
_G[name] = M -- 将模块表加入到全局变量中
package.loaded[name] = M -- 将模块表加入到package.loaded中,防止多次加载
setfenv(1,M) -- 将模块表设置为函数的环境表,这使得模块中的所有操作是以在模块表中的,这样定义函数就直接定义在模块表中
-- 这也使得之前的环境中的任何东西将无法被使用,这里就包括了_G
在使用了module函数的脚本,使用require并不能返回一个table,而是一个bool值,这个值告诉你是否加载成功
require一个使用了module函数的脚本,结果会被存在_G的全局表里
package.seeall
解决了module 独立环境无法使用之前环境中的全局变量
module ("aModule",package.seeall)
-- 相当于
local name = "aModule"
local M = {}
_G[name] = M
package.loaded[name] = M
setmetatable(M,{__index = _G})
setfenv(1,M)
static int ll_seeall (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
if (!lua_getmetatable(L, 1)) {
lua_createtable(L, 0, 1); /* create new metatable */
lua_pushvalue(L, -1);
lua_setmetatable(L, 1);
}
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index"); /* mt.__index = _G */
return 0;
}
setfenv
当我们在全局环境中定义变量时经常会有命名冲突,尤其是在使用一些库的时候,变量声明可能会发生覆盖,这时候就需要一个非全局的环境来解决这问题。
setfenv(f, table):设置一个函数的环境
(1)当第一个参数为一个函数时,表示设置该函数的环境
(2)当第一个参数为一个数字时,为1代表当前函数,2代表调用自己的函数,3代表调用自己的函数的函数,以此类推
所谓函数的环境,其实一个环境就是一个表,该函数被限定为只能访问该表中的域,或在函数体内自己定义的变量。
a = 10
newfenv = {_G = _G}
setfenv(1, newfenv)
_G.print(1) -- 1
_G.print(_G.a) -- 10
_G.print(a) -- nil 注意此处是nil,新环境没有a域,但可以通过_G.a访问_G的a域