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

Lua5.3 注册表 _G _ENV

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

注明来源:http://blog.csdn.net/murisly/article/details/46518551

注册表的描述,借用PIL中的一段话:

registry 一直位于一个由 LUA_REGISTRYINDEX 定义的值所对应的假索引(pseudo-index)的位置。一个假索引除了他对应的值不在栈中之外,其他都类似于栈中的索引。Lua API 中大部分接受索引作为参数的函数,也都可以接受假索引作为参数—除了那些操作栈本身的函数,比如 lua_remove,lua_insert。例如,为了获取以键值 "Key" 保

存在 registry 中的值,使用下面的代码:

[cpp] view plaincopy
 
 
  1. lua_pushstring(L, "Key");  
  2. lua_gettable(L, LUA_REGISTRYINDEX);  

 

由于这个表是所有的lua库所共享的,所以key值也一定要注意。云大也给了一些去key值的参考方法

函数中,取注册表键值有这样的代码,可以看出注册表存储在 global_State 结构的 l_registry 变量中

[cpp] view plaincopy
 
 
  1. static TValue *index2addr (lua_State *L, int idx)  
  2. else if (idx == LUA_REGISTRYINDEX)  /*注册表索引*/  
  3. return &G(L)->l_registry;  

注册表这个量在lua CApi可以访问,lua脚本中访问不了。Lua中可以访问的是 _G 这个全局变量。

[plain] view plaincopy
 
 
  1. for i,v in pairs(_G) do  
  2.     print("name:", i, ", type:", type(v));  
  3. end  

这可以看到当前全局量里面所包含的值。那么全局量保存在那个位置呢?可以在lua_getglobal的源代码

[cpp] view plaincopy
 
 
  1. LUA_API void lua_getglobal (lua_State *L, const char *var) {  
  2.   Table *reg = hvalue(&G(L)->l_registry);  
  3.   const TValue *gt;  /* global table */  
  4.   lua_lock(L);  
  5.   gt = luaH_getint(reg, LUA_RIDX_GLOBALS);  
  6.   setsvalue2s(L, L->top++, luaS_new(L, var));  
  7.   luaV_gettable(L, gt, L->top - 1, L->top - 1);  
  8.   lua_unlock(L);  
  9. }  

可以看出获得全局变量,先是获得注册表的值,然后注册表中key为 LUA_RIDX_GLOBALS 的表就是全局表。Lua.h中定义了这个宏。

[cpp] view plaincopy
 
 
  1. #define LUA_RIDX_MAINTHREAD 1  
  2. #define LUA_RIDX_GLOBALS    2  
  3. #define LUA_RIDX_LAST       LUA_RIDX_GLOBALS  

当前也就是构建了这样的一个状态



再来看看 _ENV 这个量

Print(_G);   -->table:003C27D8

Print(_ENV); -->table:003C27D8

这里看出两个指向的是同一个table。那么这两个是什么关系呢?Lua官方说明文档中:

When Lua loads a chunk, the default value for its _ENV upvalue is the global environment (see load). 

Therefore, by default, free names in Lua code refer to entries in the global environment 

(and, therefore, they are also called global variables).

 Moreover, all standard libraries are loaded in the global environment and some functions there operate on that environment. 

You can use load (or loadfile) to load a chunk with a different environment. 

(In C, you have to load the chunk and then change the value of its first upvalue.)

 

关于chuck的解释:

The unit of compilation of Lua is called a chunk. Syntactically, a chunk is simply a block。

A chunk can be stored in a file or in a string inside the host program. 

To execute a chunk, Lua first loads it, precompiling the chunk's code into instructions for a virtual machine,

 and then Lua executes the compiled code with an interpreter for the virtual machine.

 

一个chunk就是lua的一个解释单元,可以存储在文件或者字符串中。对于每一个chunk,都有一个叫_ENV的upvalue,此时_ENV的初值就是_G。在chunk内的函数,都会有这个upvalue值。修改当前的chunk的 _ENV,也就修改了_G,那么在该代码块中加入的非local变量,可以直接通过名称在其他chunk中访问到(当然该chunk的_ENV 也得是 _G)。

所以不规范得命名很容易影响其他模块。为了避免这种情况,变量尽量申请为local类型。利用_G和表元表和元方法,即可以强制声明全局变量。

[plain] view plaincopy
 
 
  1. local oldprint = print;  
  2. local oldload = load;  
  3. local oldpairs = pairs;  
  4. local _tenv = {};  
  5. _tenv.tprint = print;  
  6. _tenv.tpairs = pairs;  
  7.   
  8.   
  9. oldprint(_ENV);    -->table: 00A888D8  
  10. oldprint(_ENV._G); -->table: 00A888D8  
  11. oldprint(_G);      -->table: 00A888D8  
  12.   
  13. local _tg = _G;  -->_G 通过 _tg 保存起来  
  14. _G = {};         
  15. _ENV = _tenv;  
  16. x = 1;  
  17. for i,v in tpairs(_ENV) do  
  18.     tprint(i);   -->tprint  
  19. end           -->x  
  20.                       -->tpairs  
  21.   
  22. oldprint(_ENV); -->table: 00A8E660  
  23. oldprint(_G);   -->nil(此时这两个表指向了不同的地方)  
  24.   
  25. --test这个chunk内,使用的 _ENV 是 _tenv。这里 _ENV 添加了变量 y   
  26. local a = oldload("y = 1; for i,v in tpairs(_ENV) do tprint(i); end", "test", "t", _tenv);  
  27. a();  
  28. --访问另一个chunk,使用同样的 _ENV , y值可以直接访问  
  29. local b = oldload("y = y + 1;", "test", "t", _tenv);  
  30. b();  
  31.   
  32. oldprint(_tenv.y); -->2  
  33. oldprint(_ENV.y);  -->2  
  34. oldprint(_tg.y) -->nil  

 

这里可以看出,当前chunk 的 _ENV 改变了,不会改变全局的 _G(除非此时 _ENV 就是指向的 _G)。在加载一个chunk的时候可以设置 _ENV,说明可以让chunk在特定的环境中运行。获取一个独立运行环境的函数,可以修改 _ENV 。

[plain] view plaincopy
 
 
  1. function testbar(env)  
  2.     local _ENV = env;  
  3.     _ENV.x = 1;  
  4.     return function ()  
  5.         return _ENV.x;  
  6.     end  
  7. end  
  8.   
  9. local env = {};  
  10. local f = testbar(env);  
  11. print(_ENV.x);  
  12. print(f());  


注明来源:http://blog.csdn.net/murisly/article/details/46518551


鲜花

握手

雷人

路过

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

请发表评论

全部评论

专题导读
上一篇:
如何让EditPlus支持LUA(转)发布时间:2022-07-22
下一篇:
cocos-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