Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

操作 Table

Table 是 Lua 唯一的数据结构,掌握 C API 中的 table 操作至关重要。

创建 Table

lua_newtable(L);           // 等价于 lua_createtable(L, 0, 0) 
lua_createtable(L, narr, nrec);  // 预分配数组部分 narr、哈希部分 nrec 

读写字段

假设栈顶是一个 table。

通用 API(支持任意类型键)

// 读:t[key]
lua_pushstring(L, "name");     // 压入 key
lua_gettable(L, -2);           // 查询,弹出 key,结果压栈
// 此时栈顶是 t["name"] 的值

// 写:t[key] = value
lua_pushstring(L, "name");     // 压入 key
lua_pushstring(L, "Alice");    // 压入 value
lua_settable(L, -3);           // 弹出 key 和 value,设置到 table

lua_gettablelua_settable 会触发 __index / __newindex 元方法。

便捷 API(字符串键与整数键)

当 key 为字符串或整数时,可使用更便捷的函数,无需手动压入 key:

// 字符串键:t.name = "Alice"
lua_pushstring(L, "Alice");    // 压入 value
lua_setfield(L, -2, "name");   // 弹出 value,设置到 table

// 整数键:t[1] = "lua"
lua_pushstring(L, "lua");      // 压入 value
lua_seti(L, -2, 1);            // 弹出 value,设置到 table

lua_getfield / lua_setfield / lua_geti / lua_seti 同样会触发对应的元方法。

便捷 API 汇总

操作函数说明
获取整数键值lua_geti(L, idx, n)t[n],结果压栈
设置整数键值lua_seti(L, idx, n)t[n] = value,弹出栈顶 value
获取字符串键值lua_getfield(L, idx, k)t.k,结果压栈
设置字符串键值lua_setfield(L, idx, k)t.k = v,弹出栈顶 v
原始获取lua_rawget / lua_rawgeti / lua_rawgetp绕过元方法
原始设置lua_rawset / lua_rawseti / lua_rawsetp绕过元方法

遍历 Table

lua_pushnil(L);   // 第一个 key 
while (lua_next(L, table_index) != 0) {
        // 此时栈顶:value (-1), key (-2) 
        // 处理 key-value... 

    lua_pop(L, 1);       // 弹出 value,保留 key 供下一次迭代 
}

lua_next 直接遍历 table 的内部存储,不触发任何元方法(包括 __pairs)。如果需要仅遍历数组部分,可用 lua_rawlen 获取长度后按整数下标遍历。

数组长度

lua_Integer len = luaL_len(L, -1);   // 调用 #t,触发 __len 
size_t rawlen = lua_rawlen(L, -1);   // 不触发元方法 

完整代码


#include <assert.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    lua_newtable(L);

    lua_pushstring(L, "Alice");
    lua_setfield(L, -2, "name");
    lua_pushinteger(L, 30);
    lua_setfield(L, -2, "age");

    lua_pushstring(L, "lua");
    lua_seti(L, -2, 1);
    lua_pushstring(L, "c");
    lua_seti(L, -2, 2);

    lua_getfield(L, -1, "name");
    assert(strcmp(lua_tostring(L, -1), "Alice") == 0);
    lua_pop(L, 1);

    lua_geti(L, -1, 1);
    assert(strcmp(lua_tostring(L, -1), "lua") == 0);
    lua_pop(L, 1);

    assert(luaL_len(L, -1) == 2);

    lua_rawgeti(L, -1, 1);
    assert(strcmp(lua_tostring(L, -1), "lua") == 0);
    lua_pop(L, 1);

    lua_pop(L, 1);

    lua_close(L);
    puts("05-tables: ok");
    return 0;
}