在 C++ 中遍历 Lua table

  最近一个项目里要用到 Lua,于是有机会来学习如何在 C++ 里嵌入 Lua。用编译型语言和脚本语言协作来开发软件是不错的主意,Emacs 的 C + Lisp 就是一个展示这种具有良好扩展性和弹性架构很好的例子。其实我们身边还有很多这样的例子,比如在浏览器里使用 JavaScript,这就是在宿主程序里通过脚本语言调用宿主功能最典型的例子。UltraEdit 的新版里也集成了通过 JavaScript 来使用编辑器功能的特性。

  今天遇到了一个问题,就是通过 Lua C API 来取一个 table 中的数据。貌似 Lua 里没有判断指定 key 是否存在的 API。如果直接 lua_pushstring() 然后再 lua_gettable(),而指定的 key 又不存在的话程序会直接退出,比较的不爽。

  Google 了一把发现一种遍历 table 的方法,这样就可以在遍历的过程中去检查指定的 key 是否存在了。可以用 lua_next() 来遍历 table,但是这个 API 理解起来还是需要点时间的,特此记录一笔。使用 lua_next() 的一般形式是:

  1. // 进行下面步骤前先将 table 压入栈顶
  2.  int nIndex = lua_gettop( pLua )// 取 table 索引值
  3.  lua_pushnil( pLua )// nil 入栈作为初始 key
  4.  while( 0 != lua_next( pLua, nIndex ) )
  5.  {
  6.      // 现在栈顶(-1)是 value,-2 位置是对应的 key
  7.      // 这里可以判断 key 是什么并且对 value 进行各种处理
  8.      lua_pop( pLua, 1 )// 弹出 value,让 key 留在栈顶
  9.  }
  10.  // 现在栈顶是 table

lua_next() 这个函数的工作过程是:
1) 先从栈顶弹出一个 key
2) 从栈指定位置的 table 里取下一对 key-value,先将 key 入栈再将 value 入栈
3) 如果第 2 步成功则返回非 0 值,否则返回 0,并且不向栈中压入任何值

第 2 步中从 table 里取出所谓“下一对 key-value”是相对于第 1 步中弹出的 key 的。table 里第一对 key-value 的前面没有数据,所以先用 lua_pushnil() 压入一个 nil 充当初始 key。

注意开始的时候先用 lua_gettop() 取了一下 table 在栈中的正索引(前面说过了,在进行这个 lua_next() 过程之前先将 table 入栈,所以栈大小就是 table 的正索引),后面的 lua_next() 过程中不断的有元素出入栈,所以使用正索引来定位 table 比较方便。

到了 table 中已经没有 key-value 对时,lua_next() 先弹出最后一个 key,然后发现已经没有数据了会返回 0,while 循环结束。所以这个 lua_next() 过程结束以后 table 就又位于栈顶了。

  刚接触 Lua 不久,所以遇到一个问题罗嗦了大半天,其实 Lua 跟宿主打交道都靠这个 stack,这一点跟 MSIL 很像!掌握了 stack 的使用以后在 C/C++ 里嵌入 Lua 就不难了。

Leave a Reply