zoukankan      html  css  js  c++  java
  • Lua5.3 注册表 _G _ENV

    注明来源: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

  • 相关阅读:
    宏定义中的常见使用
    VS 对于LINK fatal Error 问题 解决方案
    cocos2d-x中常见的场景切换
    给新建的Cocos2d-x 3.X的Win32工程添加CocoStudio库
    2048之军衔篇 反馈 有事留言
    http 错误代码表
    华为S5700交换机初始化和配置SSH和TELNET远程登录方法
    Linux修改网卡名
    Linux如何配置bond
    linux系统下如何挂载NTFS移动硬盘
  • 原文地址:https://www.cnblogs.com/vanishfan/p/6856411.html
Copyright © 2011-2022 走看看