- 映射式表不支持ipairs枚举。
- 以初始化{}创建表时,不支持用变量表示的key值。
- 枚举表时,pairs枚举的是随机次序。ipairs保证有序,但适用于数组(列表),不能用于映射表。
- 对映射式表,以数字0作为key时,虽然insert时是第一个,但往往不会放在第一条,导致pairs枚举时,极容易出来乱序。当然,如果要保证排序,就该避免用映射表。
一、残留__metatable表

在图1,cpp_query_goods_是aplt_leagor_khome表中字段,类型user_data。给它设了个元表,名称“cpp.vquery_goods”,元表有三个方法:__gc、__index和reload。如果运行正常,元表中方法的[function]应该会显示对应的C代码实现函数,见图2。

那为什么会出现图1中[function]是空?
- 已存在个aplt_leagor_khome表,它有cpp_query_goods_字段,并设了元表cpp.vquery_goods,并有__gc等三个方法,此时[function]都指向有效C代码实现函数。
- 销毁aplt_leagor_khome表,即aplt_leagor_khome置nil。
- 垃圾回收:lua_gc(L, LUA_GCCOLLECT);
- 立即再次新建aplt_leagor_khome,再次增加cpp_query_goods_字段,只是增加,没给重新设元表,于是有可能会出现图1情况。不过更多时候是出现有这个表,而且__gc三个方法指向之前的有效C函数。
一旦出现图1情况,如果lua有类似以下代码。
cpp_query_goods是个类型user_data的变量。 cpp_query_goods_:reload();
由于reload指向一个无效C函数(图1调试窗口显示为空),cpp_query_goods_:reload将抛出图1所示异常。
第二次增加cpp_query_goods_字段,就没增加“cpp.vquery_goods”元表,可它的确存在了。不清楚这里面怎么个细节,猜测和lua的垃圾回收机制有关。
要避免列留元表造成的潜在干扰,一是在垃圾回收cpp_query_goods_时,加上手动释放元表,这样一来,第二次创建时,这元表应该肯定没了。目前rose没用这方法,代替要增加cpp_query_goods_字段时,不判断元表是不是存在,批正都重要设置元表。这也就保证了,一旦出现列留表,会把表中结应的C函数设到正确值。看下面代代码。
void luaW_pushvquery_goods(lua_State* L, tquery_goods& widget) { tquery_goods** v = (tquery_goods**)lua_newuserdata(L, sizeof(tquery_goods*)); *v = &widget; luaL_newmetatable(L, "cpp.vquery_goods"); ....设置元表
不要使用以下逻辑。
if (luaL_newmetatable(L, "cpp.vquery_goods")) { ....设置元表 }
当存在残留元表时,luaL_newmetatable会返回false,设置元表操作不执行了,有可能造成列留元表错,造成类似图1异常。
}
luaL_newmetatable会确保有一个名称是"cpp.vquery_goods"元表,并把该元表入栈。如果已经有此元表,luaL_newmetatable只是入栈,然后返回false。如果没有,新建一个,返回true。