注明來源:http://blog.csdn.net/murisly/article/details/46518551
注冊表的描述,借用PIL中的一段話:
registry 一直位於一個由 LUA_REGISTRYINDEX 定義的值所對應的假索引(pseudo-index)的位置。一個假索引除了他對應的值不在棧中之外,其他都類似於棧中的索引。Lua API 中大部分接受索引作為參數的函數,也都可以接受假索引作為參數—除了那些操作棧本身的函數,比如 lua_remove,lua_insert。例如,為了獲取以鍵值 "Key" 保
存在 registry 中的值,使用下面的代碼:
- lua_pushstring(L, "Key");
- lua_gettable(L, LUA_REGISTRYINDEX);
由於這個表是所有的lua庫所共享的,所以key值也一定要注意。雲大也給了一些去key值的參考方法。
函數中,取注冊表鍵值有這樣的代碼,可以看出注冊表存儲在 global_State 結構的 l_registry 變量中
- static TValue *index2addr (lua_State *L, int idx)
- else if (idx == LUA_REGISTRYINDEX) /*注冊表索引*/
- return &G(L)->l_registry;
注冊表這個量在lua CApi可以訪問,lua腳本中訪問不了。Lua中可以訪問的是 _G 這個全局變量。
- for i,v in pairs(_G) do
- print("name:", i, ", type:", type(v));
- end
這可以看到當前全局量里面所包含的值。那么全局量保存在那個位置呢?可以在lua_getglobal的源代碼
- LUA_API void lua_getglobal (lua_State *L, const char *var) {
- Table *reg = hvalue(&G(L)->l_registry);
- const TValue *gt; /* global table */
- lua_lock(L);
- gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
- setsvalue2s(L, L->top++, luaS_new(L, var));
- luaV_gettable(L, gt, L->top - 1, L->top - 1);
- lua_unlock(L);
- }
可以看出獲得全局變量,先是獲得注冊表的值,然后注冊表中key為 LUA_RIDX_GLOBALS 的表就是全局表。Lua.h中定義了這個宏。
- #define LUA_RIDX_MAINTHREAD 1
- #define LUA_RIDX_GLOBALS 2
- #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和表元表和元方法,即可以強制聲明全局變量。
- local oldprint = print;
- local oldload = load;
- local oldpairs = pairs;
- local _tenv = {};
- _tenv.tprint = print;
- _tenv.tpairs = pairs;
- oldprint(_ENV); -->table: 00A888D8
- oldprint(_ENV._G); -->table: 00A888D8
- oldprint(_G); -->table: 00A888D8
- local _tg = _G; -->_G 通過 _tg 保存起來
- _G = {};
- _ENV = _tenv;
- x = 1;
- for i,v in tpairs(_ENV) do
- tprint(i); -->tprint
- end -->x
- -->tpairs
- oldprint(_ENV); -->table: 00A8E660
- oldprint(_G); -->nil(此時這兩個表指向了不同的地方)
- --test這個chunk內,使用的 _ENV 是 _tenv。這里 _ENV 添加了變量 y
- local a = oldload("y = 1; for i,v in tpairs(_ENV) do tprint(i); end", "test", "t", _tenv);
- a();
- --訪問另一個chunk,使用同樣的 _ENV , y值可以直接訪問
- local b = oldload("y = y + 1;", "test", "t", _tenv);
- b();
- oldprint(_tenv.y); -->2
- oldprint(_ENV.y); -->2
- oldprint(_tg.y) -->nil
這里可以看出,當前chunk 的 _ENV 改變了,不會改變全局的 _G(除非此時 _ENV 就是指向的 _G)。在加載一個chunk的時候可以設置 _ENV,說明可以讓chunk在特定的環境中運行。獲取一個獨立運行環境的函數,可以修改 _ENV 。
- function testbar(env)
- local _ENV = env;
- _ENV.x = 1;
- return function ()
- return _ENV.x;
- end
- end
- local env = {};
- local f = testbar(env);
- print(_ENV.x);
- print(f());
注明來源:http://blog.csdn.net/murisly/article/details/46518551