Lua C Api lua_gettable 、lua_settable 、lua_next 使用詳解


之前一直沒理清lua_gettable和lua_settable的使用,今天理清了,順便就做下筆記了。
1.lua_gettable


void lua_gettable (lua_State *L, int index);

t[k] 值壓入堆棧,這里的 t 是指有效索引 index 指向的值,而 k 則是棧頂放的值。這個函數會彈出堆棧上的 key,把結果放在棧上相同位置。

下面舉個例子:

// 將一個key放到棧頂,這個key為1。如果你的key是字符串,那就用lua_pushstring。

lua_pushnumber(L, 1);

// table一開始是在棧頂,即-1處的,但上面的語句壓入了一個值,棧頂變-2了。

// lua_gettable的作用就是以棧頂的值作為key來訪問-2位置上的table。

lua_gettable(L, -2);

這時table中的第1個元素的值就放到棧頂了,你想怎么使用就怎么使用吧。

獲取table元素:

  * 將元素的key壓入到棧中,用 lua_gettable(Lua_state,index)

  * 對於字符串索引,可以用lua_getfield(Lua_state,index,key)來直接獲取,

  如:lua_getfield(stack, -1, "loaded");等價於 lua_pushstring(L,"loaded") lua_gettable(L,-2);

上面說的是訪問table中的一個元素的方法,那要怎么樣遍歷table中的所有元素呢?

1)如果table是一個以連續的整形作為key的table, 可以用下面方法:

int size = lua_objlen(L,-1);//相關於#table  
for(int i = 1; i <= size; i++)  
{  
lua_pushnumber(L, i);  
lua_gettable(L, -2);  
//這時table[i]的值在棧頂了  
lua_pop(L, 1);//把棧頂的值移出棧,保證棧頂是table以便遍歷。  
};  

2)如果table中的key是任意值呢?可以用下面的方法:

lua_pushnill(L);  
while(lua_next(L, -2))  
{  
//這時值在-1(棧頂)處,key在-2處。  
lua_pop(L, 1);//把棧頂的值移出棧,讓key成為棧頂以便繼續遍歷  
}  

這里重點說明一下lua_next。

它執行操作是這樣的,以棧頂元素為key,先判斷上一個key的值(這個值放在棧頂,如果是nil,則表示當前取出的是table中第一個元素的值),然后得到當前的key和value。

這時先把棧頂出棧,將新key進棧,后將value進棧。這樣棧頂就是table中第一個遍歷到的元素的值。用完這個值后,我們要把這個值出棧,讓新key在棧頂以便繼續遍歷。當根據上一個key值算不出下一個key值時(其實這時候key的是多少並不重要,只要不為nil就行,因為為nil會返回table的第一個元素),lua_next返回0,結束循環。

2.lua_settable
void lua_settable (lua_State *L, int index);

作一個等價於 t[k] = v 的操作, 這里 t 是一個給定有效索引 index 處的值, v 指棧頂的值, 而 k 是棧頂之下的那個值。

這個函數會把鍵和值都從堆棧中彈出。

其實這個解釋的意思就是,lua_settable 會把棧頂作為value,棧頂的下一個作為key設置到index指向的table,最后把這兩個彈出彈出棧,這時候settable完成。

3.lua_next
int lua_next (lua_State *L, int index);

從棧上彈出一個 key(鍵),然后把索引指定的表中 key-value(健值)對壓入堆棧(指定 key 后面的下一 (next) 對)。如果表中以無更多元素,那么lua_next 將返回 0 (什么也不壓入堆棧)。

典型的遍歷方法是這樣的:

     /* table 放在索引 't' 處 */
     lua_pushnil(L);  /* 第一個 key */
     while (lua_next(L, t) != 0) {
       /* 用一下 'key' (在索引 -2 處) 和 'value' (在索引 -1 處) */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* 移除 'value' ;保留 'key' 做下一次迭代 */
       lua_pop(L, 1);
     }

在遍歷一張表的時候,不要直接對 key 調用 lua_tolstring ,除非你知道這個 key 一定是一個字符串。調用 lua_tolstring 有可能改變給定索引位置的值;這會對下一次調用 lua_next 造成影響。

 

 最后我們以一段c調用lua的loaded表並且設置符合某個規章的key將它的value設置為nil,為列:

 1 ua_getglobal(stack, "package");                         /* L: package,獲得package,在棧定 */
 2 lua_getfield(stack, -1, "loaded");                       /* L: package loaded,獲得表,在棧頂*/
 3 lua_pushnil(stack);                                     /* L: package loaded nil */
 4 while ( 0 != lua_next(stack, -2 ) ) /* L: package loaded, key, value,上一個棧頂為nil,彈出nil,獲得表的第一個key和value,壓入棧 */
 5 {
 6     //CCLOG("%s - %s \n", tolua_tostring(stack, -2, ""), lua_typename(stack, lua_type(stack, -1)));
 7     std::string key=tolua_tostring(stack, -2, "");  /*這時候棧頂得下一個,是key*/
 8     std::string tableKey =key;                      /*下面是對key的一段處理*/
 9     int found = tableKey.rfind(".lua");
10     if (found!=std::string::npos)
11         tableKey = tableKey.substr(0,found);
12     tableKey=replaceAll(tableKey,".","/");
13     tableKey=replaceAll(tableKey,"\\","/");
14     tableKey.append(".lua");
15     found = fileName.rfind(tableKey);
16     if (0 == found || ( found!=std::string::npos && fileName.at(found-1) == '/'))
17     {
18         lua_pushstring(stack, key.c_str());  /*package loaded, key, value,newkey, 將key,壓入棧頂*/
19         lua_pushnil(stack);                 /* pakage,loaded(table)(-5),key(-4),value(-3),key(-2),nil(-1)*/
20         if (lua_istable(stack, -5)) /*判讀棧頂往下第五個是不是table*/
21         {
22             /*結果將key對應的值置為nil*/
23             lua_settable(stack, -5);/*pakage,loaded(table),key,value,  將棧頂兩個元素作為key和value設置給table,彈出棧頂兩個元素*/
24         }
25     }
26     lua_pop(stack, 1); /*pakage,loaded(table),key  彈出value,留下key作為下一個next*/
27 }
28 lua_pop(stack, 2); /*棧平衡*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM