Lua5.3 註冊表 _G _ENV

註明來源:http://blog.csdn.net/murisly/article/details/46518551html

註冊表的描述,借用PIL中的一段話:ide

registry 一直位於一個由 LUA_REGISTRYINDEX 定義的值所對應的假索引(pseudo-index)的位置。一個假索引除了他對應的值不在棧中以外,其餘都相似於棧中的索引。Lua API 中大部分接受索引做爲參數的函數,也均可以接受假索引做爲參數—除了那些操做棧自己的函數,好比 lua_remove,lua_insert。例如,爲了獲取以鍵值 "Key" 保函數

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

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

 

因爲這個表是全部的lua庫所共享的,因此key值也必定要注意。雲大也給了一些去key值的參考方法spa

函數中,取註冊表鍵值有這樣的代碼,能夠看出註冊表存儲在 global_State 結構的 l_registry 變量中.net

[cpp]  view plain copy
 
 
  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 這個全局變量。code

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

這能夠看到當前全局量裏面所包含的值。那麼全局量保存在那個位置呢?能夠在lua_getglobal的源代碼htm

[cpp]  view plain copy
 
 
  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中定義了這個宏。blog

[cpp]  view plain copy
 
 
  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 plain copy
 
 
  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 plain copy
 
 
  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

相關文章
相關標籤/搜索