有没有一种方法可以使Lua 5.1填充以支持比较元方法?

时间:2020-01-09 12:51:45

标签: lua lua-table

大多数Lua版本都支持表上的算术比较运算符。例如,考虑这种情况,它简化为用于处理各种单位长度的抽象:

local function convert_units (input)
    if type(input) ~= "table" then
        return input
    else
        if input.unit == "cm" then
            return input.amount * 10
        else
            return input.amount
        end
    end
end

local mt = {
    __lt = function (self, other)
        return convert_units(self) < convert_units(other)
    end
}

local a = {
    amount = 1.2,
    unit = "cm"
}

local b = {
    amount = 14,
    unit = "mm"
}

setmetatable(a, mt)
setmetatable(b, mt)

print(a < b)

这将输出true,因为元表具有__lt方法,该方法将对象转换为兼容单元,然后进行比较。该代码将在Lua 5.1、5.2和5.3中工作

当您尝试错过匹配这样的类型时,问题就来了:

print (a < 13)

这将在Lua 5.2和5.3中起作用,但是在Lua 5.1中它将引发错误:

lua5.1:尝试将数字与表格进行比较

数学元方法完全可以在比较的一侧处理原始数字,但是Lua 5.1甚至拒绝尝试。

不幸的是,我需要能够支持一系列Lua口译员。最小公分母是Lua 5.1,这意味着要么总是将原始数字站点设为相似的对象实例,要么总是在编写比较时使用convert_units()

鉴于volume and complexity of code involved,如果我能使Lua 5.1能够支持它,那将是非常好的。有什么方法可以说服它允许将表格与数字进行比较?

1 个答案:

答案 0 :(得分:3)

恐怕是不可能的。如果将luaV_lessthan的实现与5.1和5.3进行比较,可能会有所帮助:

int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
  int res;
  if (ttype(l) != ttype(r))
    return luaG_ordererror(L, l, r);
  else if (ttisnumber(l))
    return luai_numlt(nvalue(l), nvalue(r));
  else if (ttisstring(l))
    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
  else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
    return res;
  return luaG_ordererror(L, l, r);
}

5.3:

int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
  int res;
  if (ttisnumber(l) && ttisnumber(r))  /* both operands are numbers? */
    return LTnum(l, r);
  else if (ttisstring(l) && ttisstring(r))  /* both are strings? */
    return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
  else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0)  /* no metamethod? */
    luaG_ordererror(L, l, r);  /* error */
  return res;
}

如您所见,执行lessthan函数时(由于在代码中发现<而发出了这些函数),这些实现会做很多不同的事情。当旧的解释器看到不同类型的操作数时,它很快就会摆脱困境。因此,根本无法将展开的数字与表格进行比较。