此第一版是針對 Lua 5.0 編寫。儘管在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您也將協助 支援 Lua 專案。
![]() |
使用 Lua 進行程式設計 | ![]() |
第四部分。C API 第 28 章。C 中的使用者定義類型 |
我們首先關注的是如何在 Lua 中表示陣列值。Lua 提供了一個專門針對此目的的基本類型:使用者資料。使用者資料在 Lua 中提供一個原始記憶體區域,不含任何預定義的運算。
Lua API 提供下列函式來建立使用者資料
void *lua_newuserdata (lua_State *L, size_t size);
lua_newuserdata
函式會配置一個具有指定大小的記憶體區塊,將對應的使用者資料推入堆疊,並傳回區塊位址。如果您因某些原因需要透過其他方式配置記憶體,則可以很輕鬆地建立一個大小為指標的使用者資料,並將一個指向實際記憶體區塊的指標儲存在其中。我們將在下一章中看到此技術的範例。
使用 lua_newuserdata
,建立新陣列的函式如下
static int newarray (lua_State *L) { int n = luaL_checkint(L, 1); size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double); NumArray *a = (NumArray *)lua_newuserdata(L, nbytes); a->size = n; return 1; /* new userdatum is already on the stack */ }(
luaL_checkint
函式是 luaL_checknumber
的整數變體。)一旦 newarray
在 Lua 中註冊,您就可以使用類似 a = array.new(1000)
的陳述式建立新陣列。
若要儲存一個項目,我們將使用類似 array.set(array, index, value)
的呼叫。稍後我們將看到如何使用元表來支援更傳統的語法 array[index] = value
。對於這兩種表示法,底層函式都是相同的。它假設索引從 1 開始,如同 Lua 中常見的。
static int setarray (lua_State *L) { NumArray *a = (NumArray *)lua_touserdata(L, 1); int index = luaL_checkint(L, 2); double value = luaL_checknumber(L, 3); luaL_argcheck(L, a != NULL, 1, "`array' expected"); luaL_argcheck(L, 1 <= index && index <= a->size, 2, "index out of range"); a->values[index-1] = value; return 0; }
luaL_argcheck
函式會檢查指定的條件,並在必要時引發錯誤。因此,如果我們使用錯誤的引數呼叫 setarray
,我們會收到一個說明性的錯誤訊息
array.set(a, 11, 0) --> stdin:1: bad argument #1 to `set' (`array' expected)
下一個函式會擷取一個項目
static int getarray (lua_State *L) { NumArray *a = (NumArray *)lua_touserdata(L, 1); int index = luaL_checkint(L, 2); luaL_argcheck(L, a != NULL, 1, "`array' expected"); luaL_argcheck(L, 1 <= index && index <= a->size, 2, "index out of range"); lua_pushnumber(L, a->values[index-1]); return 1; }我們定義另一個函式來擷取陣列的大小
static int getsize (lua_State *L) { NumArray *a = (NumArray *)lua_touserdata(L, 1); luaL_argcheck(L, a != NULL, 1, "`array' expected"); lua_pushnumber(L, a->size); return 1; }最後,我們需要一些額外的程式碼來初始化我們的函式庫
static const struct luaL_reg arraylib [] = { {"new", newarray}, {"set", setarray}, {"get", getarray}, {"size", getsize}, {NULL, NULL} }; int luaopen_array (lua_State *L) { luaL_openlib(L, "array", arraylib, 0); return 1; }我們再次使用輔助函式庫中的
luaL_openlib
。它會建立一個具有指定名稱的表格(在我們的範例中為 "array"
),並使用 arraylib
陣列指定的成對名稱函式填入表格。
開啟函式庫後,我們就可以在 Lua 中使用我們的類型
a = array.new(1000) print(a) --> userdata: 0x8064d48 print(array.size(a)) --> 1000 for i=1,1000 do array.set(a, i, 1/i) end print(array.get(a, 10)) --> 0.1
在 Pentium/Linux 上執行此實作時,一個具有 100K 元素的陣列會佔用 800 KB 的記憶體,正如預期;一個等效的 Lua 表格需要超過 1.5 MB。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |