• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

对lua中_ENV表的理解(lua5.2版本以后)

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

  当我拿到_ENV表的时候,会去想这个_ENV表是干什么用的? 首先看如下代码:

1 print(_ENV) --0x1d005f0
2 print(_G)   --0x1d005f0
ViewCode

  看了上面的代码,就感觉_ENV表不就是_G表吗?但_ENV表是不是全局的呢?我又打印了_G表的内容:

 1 for k , v in pairs(_G) do
 2     print(k , v)
 3 end
 4 --[[
 5 package    table: 0xad1e50
 6 setmetatable    function: 0x419220
 7 pairs    function: 0x419380
 8 require    function: 0xad3900
 9 loadfile    function: 0x419540
10 print    function: 0x418ce0
11 module    function: 0xad3890
12 rawlen    function: 0x418c50
13 load    function: 0x419430
14 getmetatable    function: 0x4195b0
15 type    function: 0x418800
16 coroutine    table: 0xad3970
17 table    table: 0xad3d10
18 error    function: 0x418f40
19 _VERSION    Lua 5.2
20 debug    table: 0xad4bb0
21 string    table: 0xad2700
22 rawequal    function: 0x418ca0
23 math    table: 0xad64d0
24 tonumber    function: 0x418870
25 bit32    table: 0xad2d60
26 os    table: 0xad3c60
27 loadstring    function: 0x419430
28 pcall    function: 0x4191c0
29 io    table: 0xad4030
30 select    function: 0x418aa0
31 unpack    function: 0x41fb40
32 collectgarbage    function: 0x418fb0
33 xpcall    function: 0x419110
34 rawset    function: 0x418bb0
35 ipairs    function: 0x4193a0
36 next    function: 0x418e20
37 rawget    function: 0x418c00
38 tostring    function: 0x418840
39 arg    table: 0xad76a0
40 _G    table: 0xad15f0
41 assert    function: 0x419680
42 dofile    function: 0x419600
43 ]]
View Code

  发现_G表中的Key是没有_ENV表的,就比较疑惑?那_ENV到是什么,是怎么样产生的?关于这两个问题我看了lua闭包

的源码,lua闭包有两种生成方式,其中一种是在lua源码加载时,会生成闭包(ps:关于闭包的整体内容会在之后的另一篇博客讲),

对于该闭包它的第一个Upvalue就是_ENV,具体代码如下:

 1 LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
 2                       const char *chunkname, const char *mode) {
 3   ZIO z;
 4   int status;
 5   lua_lock(L);
 6   if (!chunkname) chunkname = "?";
 7   luaZ_init(L, &z, reader, data);
 8   status = luaD_protectedparser(L, &z, chunkname, mode);
 9   if (status == LUA_OK) {  /* no errors? */
10     LClosure *f = clLvalue(L->top - 1);  /* get newly created function */
11     if (f->nupvalues >= 1) {  /* does it have an upvalue? */
12       /* get global table from registry */
13       Table *reg = hvalue(&G(L)->l_registry);
14       const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
15       /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
16       setobj(L, f->upvals[0]->v, gt);
17       luaC_upvalbarrier(L, f->upvals[0]);
18     }
19   }
20   lua_unlock(L);
21   return status;
22 }
lua_load中将注册表中的全局表(_G赋值给_ENV)

  所以_ENV默认会指向_G表。至于_G表是如何创建的,各位可以参考这个博客。那_ENV表的作用是什么呢?

  _ENV表的作用:表示当前代码块的环境,每一个代码块的环境都有一张_ENV。关于代码块的解释可以看这里。我们可以看一下下面这段代码就理解了:

 1 function foorbar(env)
 2     local _ENV = env
 3     return function() print("yes") end
 4 end
 5 
 6 print(_ENV)
 7 
 8 local l_test = foorbar({})
 9 
10 print(l_test())
11 
12 --[[
13 table: 0x1a395f0
14 lua: code:3: attempt to call global 'print' (a nil value)
15 stack traceback:
16     code:3: in function 'l_test'
17     code:10: in main chunk
18     [C]: in ?
19 ]]
View Code

  上述可以看出,我们的所有内部函数都定义与一张_ENV表中,比如在print时实际上是_ENV.print(语法糖省略了),所以在代码块foorbar中_ENV被赋值为{},所以print就访问不到了。

所以_ENV表的作用实际上是充当环境,所以在5.2之后就没有全局变量这样一个说法(_ENV = _G还是有全局变量的)。这种做法类似于5.1的setfenv。关于如何实现setfenv在云风的博客有提及。

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
高性能Web服务端 PHP vs Node.js vs Nginx-Lua 的对比分析发布时间:2022-07-22
下一篇:
Lua 脚本发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap