刚刚整理了C++向Lua通过表的方式传递一维数组或向量,这篇继续补充C++如何通过表的方式向Lua传递二维数组或向量。
在上例程之前,先介绍一下关键函数lua_settable()的工作机理:
void lua_settable (lua_State *L, int index);
英文释义:Does the equivalent to t[k] = v
, where t
is the value at the given index, v
is the value at the top of the stack, and k
is the value just below the top. This function pops both the key and the value from the stack. As in Lua, this function may trigger a metamethod for the "newindex" event.
意思是说,这个函数的作用呢,等价于设置表的元素t[k] = v,t是要设置的表,k为表中的key值,v为key值对应的value。调用该函数时,保证要设置的value值v在栈顶,而key值k在栈顶下面一个,也就是-2的位置,表在-3的位置。该函数执行完后,会把key值和value值从栈中弹出。
明白了以上原理,操作二维表就会明了很多,其实跟操作一维表是一样的,只不过二维表的value值也是一个表。
画了两个lua_settable()的示意图,分别为操作一维表和二维表的过程,如下:
好了,上个例程:
C++代码:
#include <iostream>
#include <vector>
#include <string>
#include "lua.hpp"
/* 定义一个函数,将一个字符串向量中的内容压入Lua栈,并调用Lua函数对其进行处理 */
int put_2D_array_to_lua(lua_State *L, std::vector<std::vector<std::string> > str_vec)
{
lua_getglobal(L, "test_table_2D");
if(!lua_isfunction(L, -1))
{
std::cout << "Get Lua function failed!" << std::endl;
return -1;
}
lua_newtable(L);
std::cout << "---1---luaL_typename(L, -1) = " << luaL_typename(L, -1) << std::endl; //现在table位于栈顶
std::cout << "---1---luaL_typename(L, -2) = " << luaL_typename(L, -2) << std::endl; //函数位于-2位置
for(int k = 0; k < str_vec.size(); k++)
{
lua_pushinteger(L, k + 1); //压入主表key值,为1~K的连续整数
lua_newtable(L); //创建一个子表
std::cout << "---2---luaL_typename(L, -1) = " << luaL_typename(L, -1) << std::endl; //现在table位于栈顶
std::cout << "---2---luaL_typename(L, -2) = " << luaL_typename(L, -2) << std::endl; //key值位于栈顶下面,即-2位置
/* 构造主表key值对应的value值,该value值是一个子表 */
for(int i = 0; i < str_vec[k].size(); i++)
{
lua_pushinteger(L, i + 1); //压入表key值,这里是1~n的整数
lua_pushstring(L, str_vec[k][i].c_str()); // 压入key对应的value值
lua_settable(L, -3); //此时表位于-3
std::cout << "---3---luaL_typename(L, -1) = " << luaL_typename(L, -1) << std::endl; //sub table
std::cout << "---3---luaL_typename(L, -2) = " << luaL_typename(L, -2) << std::endl; // sub table index
std::cout << "---3---luaL_typename(L, -3) = " << luaL_typename(L, -3) << std::endl; //main table
}
lua_settable(L, -3); //主表位于-3
std::cout << "---5---luaL_typename(L, -1) = " << luaL_typename(L, -1) << std::endl; //主表
std::cout << "---5---luaL_typename(L, -2) = " << luaL_typename(L, -2) << std::endl; //函数
std::cout << "---5---luaL_typename(L, -3) = " << luaL_typename(L, -3) << std::endl; //空
}
lua_pcall(L, 1, 1, 0); //调用名为“test_table”的lua函数
int result = lua_tointeger(L, -1); //在栈顶读取函数的返回结果
std::cout << "result = " << result << std::endl;
lua_pop(L, 1); //将函数出栈
return result;
}
/* 初始化函数 */
lua_State* script_initialize(const char* script_name)
{
lua_State *pLua = luaL_newstate(); //创建一个Lua虚拟机
if(!pLua)
{
std::cout << "Failed to open Lua!" << std::endl;
return NULL;
}
luaL_openlibs(pLua); //将标准类库加载到Lua虚拟机
luaL_dofile(pLua, script_name); //加载并运行lua文件
return pLua;
}
int main()
{
std::vector<std::string> strs = {"My", "name", "is", "Lua"};
std::vector<std::vector<std::string> > strs_vec = {{"My", "name","is", "Lua"}, {"Hello", "Lua"}, {"I", "am", "C++"}};
lua_State* pL = script_initialize("table_test.lua");
if(!pL)
{
std::cout << "Error initialize lua state!" << std::endl;
exit(1);
}
//int num = put_array_to_lua(pL, strs);
//std::cout << "After lua call, table element num is " << num << std::endl;
int num = put_2D_array_to_lua(pL, strs_vec);
lua_close(pL);
return 0;
}
lua脚本:
function test_table_2D(mytable)
local table_len = #mytable --获取表长度
print("table size: ", table_len) --打印表长度
for idx, subtbl in pairs(mytable) do
print("sub table size: ", #subtbl) --打印子表长度
for k, v in pairs(subtbl) do --打印子表中的元素
print(v)
end
end
return table_len --返回表长度
end
运行结果:左侧为C++输出,右侧为lua输出。