lua module package.seeall选项

http://blog.codingnow.com/2006/02/lua_51_module.html

使用

module("test")

后,下面不再看的见前面的全局环境。如果在这个模块里想调用 print 输出调试信息怎么办呢?一个简单的方法是

local print=print

module("test")

这样 print 是一个 local 变量,下面也是可见的。或者可以用

local _G=_G

module("test")

那么 _G.print 也是可以用的。

当然还有一种巧妙的方式,lua 5.1 提供了一个 package.seeall 可以作为 module 的option 传入

module("test",package.seeall)

这样就 OK 了。至于它们是如何工作的,还是自己读源码会理解的清楚一些。

源码不太好读, 我们下面找文档和做实验来理解。

为啥使用了 package.seeall, 则此module就可以引用全局环境了呢?

文档:

http://www.lua.org/manual/5.1/manual.html

module (name [, ···])

This function can receive optional options after the module name, where each option is a function to be applied over the module.

package.seeall (module)

Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module.

使用package.seeall后, 会将当前module的环境表, 设置个 metatable( {__index=_G})

含义就是, 当你在module声明之后, 如果使用print函数, 则在当前module环境表中存在, 则会想_G表中搜索。

package.seeall

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;

}

测试代码

module_test.lua

module(..., package.seeall)

local print = print

local getfenv = getfenv

local tostring = tostring

local getmetatable = getmetatable

--module("module_test")

local function printTable(tbl)

for k,v in pairs(tbl) do

print("kay="..tostring(k) .. " value="..tostring(v))

end

end

varone = 1

local strkey = "vartwo"

-- 本模块环境

local env = getfenv(1)

env[strkey] = 2

print("vartwo="..vartwo)

print("getfenv(1) ="..tostring( ( getfenv(1) ) ) )

print("getfenv(1) metatable="..tostring( getmetatable( getfenv(1) ) ) )

print("--------------- before getmetatable( getfenv(1) ) -------------")

printTable( getmetatable( getfenv(1) ) )

print("--------------- after getmetatable( getfenv(1) ) -------------")

-- 调用此模块的环境

local env_caller = getfenv(2)

env["env_caller"] = env_caller

print("getfenv(2) ="..tostring(getfenv(2)))

main.lua

local testmodule = require("module_test")

var_caller = 55

print("testmodule.vartwo=" .. testmodule.vartwo)

local function printTable(tbl)

for k,v in pairs(tbl) do

print("kay="..tostring(k) .. " value="..tostring(v))

end

end

print("----------- testmodule ------------------")

printTable(testmodule)

print("----------- testmodule.env_caller ------------------")

printTable(testmodule.env_caller)

打印结果

>lua -e "io.stdout:setvbuf 'no'" "main.lua"

vartwo=2

getfenv(1) =table: 006F9438

getfenv(1) metatable=table: 006F92D0

--------------- before getmetatable( getfenv(1) ) -------------

kay=__index value=table: 006F2650

--------------- after getmetatable( getfenv(1) ) -------------

getfenv(2) =table: 006F2650

testmodule.vartwo=2

----------- testmodule ------------------

kay=_NAME value=module_test

kay=_PACKAGE value=

kay=varone value=1

kay=_M value=table: 006F9438

kay=vartwo value=2

kay=env_caller value=table: 006F2650

----------- testmodule.env_caller ------------------

kay=string value=table: 006F9730

kay=xpcall value=function: 006F6788

kay=module_test value=table: 006F9438

kay=package value=table: 006F7110

kay=tostring value=function: 006F6968

kay=print value=function: 006F6CC8

kay=os value=table: 006F9848

kay=unpack value=function: 006F6A08

kay=require value=function: 006F7C98

kay=getfenv value=function: 006F6E08

kay=setmetatable value=function: 006F66A8

kay=next value=function: 006F6C88

kay=assert value=function: 006F6D48

kay=tonumber value=function: 006F6888

kay=io value=table: 006F96E0

kay=rawequal value=function: 006F6DC8

kay=collectgarbage value=function: 006F6D28

kay=arg value=table: 006F92A8

kay=getmetatable value=function: 006F6AE8

kay=module value=function: 006F7B98

kay=rawset value=function: 006F6AA8

kay=var_caller value=55

kay=math value=table: 006F96B8

kay=debug value=table: 006F91E0

kay=pcall value=function: 006F6CE8

kay=table value=table: 006F7160

kay=newproxy value=function: 006F0568

kay=type value=function: 006F6A48

kay=coroutine value=table: 006F7340

kay=_G value=table: 006F2650

kay=select value=function: 006F6B48

kay=gcinfo value=function: 006F6D88

kay=pairs value=function: 006F0538

kay=rawget value=function: 006F6A88

kay=loadstring value=function: 006F6B08

kay=ipairs value=function: 006F2BD0

kay=_VERSION value=Lua 5.1

kay=dofile value=function: 006F6DE8

kay=setfenv value=function: 006F6A28

kay=load value=function: 006F6B88

kay=error value=function: 006F6D68

kay=loadfile value=function: 006F6DA8

>Exit code: 0