第一版是針對 Lua 5.0 編寫的。雖然對於後續版本來說,內容仍然大致適用,但有些地方還是有差異。
第四版針對 Lua 5.3,可在 Amazon 及其他書店購買。
購買本書,您還可以 贊助 Lua 專案。
![]() |
用 Lua 程式設計 | ![]() |
第四部分。C API 第 27 章。撰寫 C 函式的技巧 |
在 Lua 中,「陣列」只是一個用於特定方式的表格名稱。我們可以使用與用於操作表格相同的函式來操作陣列,即 lua_settable
和 lua_gettable
。不過,與 Lua 的一般哲學「經濟且簡潔」相反,API 提供了陣列操作的特殊函式。這樣做的原因是效能:我們經常在演算法的內部迴圈中執行陣列存取操作(例如,排序),因此在此操作中獲得的任何效能提升都可能對函式的整體效能產生重大影響。
API 提供的陣列操作函式如下:
void lua_rawgeti (lua_State *L, int index, int key); void lua_rawseti (lua_State *L, int index, int key);
lua_rawgeti
和 lua_rawseti
的說明有點令人困惑,因為它涉及兩個索引:index
指的是表格在堆疊中的位置;key
指的是元素在表格中的位置。當 t
為正數時(否則,您必須補償堆疊中的新項目),呼叫 lua_rawgeti(L, t, key)
等同於下列順序:
lua_pushnumber(L, key); lua_rawget(L, t);呼叫
lua_rawseti(L, t, key)
(同樣針對正數 t
)等同於:
lua_pushnumber(L, key); lua_insert(L, -2); /* put `key' below previous value */ lua_rawset(L, t);請注意,這兩個函式都使用原始操作。它們比較快,而且無論如何,用作陣列的表格很少使用元方法。
作為使用這些函式的具體範例,我們可以將先前 l_dir
函式的迴圈主體從
lua_pushnumber(L, i++); /* key */ lua_pushstring(L, entry->d_name); /* value */ lua_settable(L, -3);改寫為
lua_pushstring(L, entry->d_name); /* value */ lua_rawseti(L, -2, i++); /* set table at key `i' */
作為更完整的範例,下列程式碼實作了 map 函式:它將給定的函式套用至陣列的所有元素,並將每個元素替換為呼叫的結果。
int l_map (lua_State *L) { int i, n; /* 1st argument must be a table (t) */ luaL_checktype(L, 1, LUA_TTABLE); /* 2nd argument must be a function (f) */ luaL_checktype(L, 2, LUA_TFUNCTION); n = luaL_getn(L, 1); /* get size of table */ for (i=1; i<=n; i++) { lua_pushvalue(L, 2); /* push f */ lua_rawgeti(L, 1, i); /* push t[i] */ lua_call(L, 1, 1); /* call f(t[i]) */ lua_rawseti(L, 1, i); /* t[i] = result */ } return 0; /* no results */ }此範例引入了三個新函式。
luaL_checktype
函式(來自 lauxlib.h
)確保給定的引數具有給定的類型;否則,它會引發錯誤。luaL_getn
函式取得給定索引處陣列的大小(table.getn
呼叫 luaL_getn
來執行其工作)。lua_call
函式執行非保護呼叫。它類似於 lua_pcall
,但如果發生錯誤,它會擲出錯誤,而不是傳回錯誤碼。當您撰寫應用程式中的主程式碼時,不應使用 lua_call
,因為您想要捕捉任何錯誤。不過,當您撰寫函式時,通常建議使用 lua_call
;如果發生錯誤,只需留給關心它的人處理即可。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |