【问题标题】:Passing a Vector<struct> to Lua table将 Vector<struct> 传递给 Lua 表
【发布时间】:2019-01-29 19:33:17
【问题描述】:

我想通过发送一个 C++ 预格式化 Lua 表来改进下面的代码:

int GetCategory(lua_State* L)
{
    uint32 Type = CHECKVAL<int>(L, 1);
    lua_newtable(L); 
    int tbl = lua_gettop(L);
    uint32 counter = 1;
    // Struct CT { string CategoryBrandName, CategoryName }; > Vector<CT>
    auto list = sManagerMgr->GetAll(); 


    // Hack modify this to send a metatable/UserData/Table whatever is called
    for (auto& elem : list)
    {
        switch (Type)
        {
        case 1:
            lua_pushstring(L, elem->CategoryBrandName);
            break;
        case 2:
            lua_pushstring(L, elem->CategoryName);
            break;
        }
        lua_rawseti(L, tbl, counter);
        counter++;
    }

    lua_settop(L, tbl);
    return 1;
}

基本上, lua_newtable 将表推送到 lua 堆栈, lua_gettop 将采用顶部索引,即表所在的索引。 然后 lua_pushstring(L, ELEMENT); lua_rawseti(L, tbl, 计数器);将 ELEMENT 放到我们使用 gettop 获得的索引 tbl 处的表中。元素的索引是计数器的值。

但是这里的问题是我不得不调用两次函数 GetCategory 来在我的 .lua 文件中填充它。

table.insert(Group, { GetCategory(1), GetCategory(2) });

当前使用:

print(i, Group(1)[i], Group(2)[i]);

所以.. 我宁愿调用一次并直接得到这样的东西:

local Group = 
{ 
        [1] = { "elem->CategoryBrandName[1]", "elem->CategoryName[1]" },
        [2] = { "elem->CategoryBrandName[2]", "elem->CategoryName[2]" }
        --etc
};

我尝试将 elem 填充到 2D Array[1][2] 中,然后推送 Array 失败

我对表格、元表、多维数组等进行了大量研究,但找不到适合我需要或工作的东西。

有人有解决办法吗?

【问题讨论】:

    标签: c++ lua lua-table


    【解决方案1】:

    你为什么不让你的函数返回两个值呢?然后你可以写

    local Group = { GetCategories }
    

    我不是 C API 方面的专家,但我认为这可以通过调用 lua_newtable(L) 来相当容易地完成,因此如下所示:

    int GetCategories(lua_State* L) {
      lua_settop(L, 0);
      // Discard arguments so we don't have to save the top of the stack
      // and can just use numbers instead (see following lines)
      lua_newtable(L); // Index 1 on stack
      lua_newtable(L); // Index 2 on stack
    
      // Do your magic
    
      lua_settop(L, 2); // Get rid of your temp variables
      return 2; // number of values we return in Lua
    }
    

    优化提示:您可以使用lua_createtable 并告诉它每个表将有多少元素,以便 Lua 可以为其预先分配一些内存。

    编辑:我刚刚注意到这一点,但在您的代码中:

    for (auto& elem : list) {
      switch (Type) {
      case 1:
        lua_pushstring(L, elem->CategoryBrandName);
        break;
      case 2:
        lua_pushstring(L, elem->CategoryName);
        break;
      }
      lua_rawseti(L, tbl, counter);
      counter++;
    }
    

    您只需将值推入堆栈即可。对于长向量,这可能会溢出堆栈(迟早),从而导致麻烦。更好的方法是 1) 推送到堆栈 2) 插入到表中 3) 将它们弹出:

    // Modified for my suggested implementation that returns
    // two tables. They can easily be turned around here.
    for (auto& elem : list) {
      lua_pushstring(L, elem->CategoryBrandName);
      lua_rawseti(L, 1, counter++);
      lua_pop(L, 1);
    
      lua_pushstring(L, elem->CategoryName);
      lua_rawseti(L, 2, counter++);
      lua_pop(L, 1);
    }
    

    了解堆栈中的内容和不存在的内容总是一个好主意。节省一些内存不仅可以提高性能,还可以避免(Lua)堆栈溢出导致的潜在问题。

    最后一个细节:在 Lua 中你不需要 ;,除非你在一行中有两个语句 print('more readable'); print('like this'),否则使用它们被认为是不好的风格。

    【讨论】:

    • lua_rawseti 将被推离堆栈的值弹出,因此不需要显式弹出。
    • @ratchetfreak 啊,我不知道,谢谢指出:)
    • counter++ on rawseti 每次都会导致双倍递增。否则它就像一个魅力 =)
    • 啊,对不起,我先改了然后复制了xD
    【解决方案2】:

    如果有人正在寻找类似的东西,这就是我使用 lua_createtable 进行管理的方法。它按预期工作,可能需要一些改进的想法。

    int GetCategory(lua_State* L)
        {   
            int counter = 1;
            int MaxListSize = 2;
            auto Categories = sManagerMgr->GetAll();
    
            lua_createtable(L, Categories.size(), 0);
    
            for (auto& elem : Categories)
            {
                vector<string> list;
                list.reserve(MaxListSize);
    
                list.emplace_back(elem->CategoryBrandName);
                list.emplace_back(elem->CategoryName);
    
                Macro::Push(L, counter); // custom
                lua_createtable(L, 0, MaxListSize);
    
                for (int i = 1; i <= MaxListSize; i++)
                {
                    Macro::Push(L, list.at(i - 1)); // custom
                    lua_rawseti(L, -2, i);
                }
    
                lua_settable(L, -3);
                list.clear();
                counter++;
            }
            return 1;
        }
    

    会产生类似于

    的输出
    local Group = 
    { 
            [1] = { "elem->CategoryBrandName[1]", "elem->CategoryName[2]" },
            [2] = { "elem->CategoryBrandName[1]", "elem->CategoryName[2]" }
            --etc
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-20
      • 2015-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      • 1970-01-01
      相关资源
      最近更新 更多