第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些差异。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还将帮助支持 Lua 项目


27.1 – 数组操作

在 Lua 中,“数组”只是以特定方式使用的表的名称。我们可以使用与操作表相同的函数来操作数组,即 lua_settablelua_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_rawgetilua_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' */

作为一个更完整的示例,以下代码实现了映射函数:它将给定函数应用于数组的所有元素,用调用的结果替换每个元素。

    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;如果发生错误,只需将其留给关心它的人即可。