【问题标题】:Is there a way to shim Lua 5.1 to support comparison meta methods?有没有办法让 Lua 5.1 支持比较元方法?
【发布时间】:2020-04-27 02:01:03
【问题描述】:

大多数 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 支持这一点,那就太好了。有什么方法可以说服它允许将表格与数字进行比较?

【问题讨论】:

  • 你可以通过使用 LuaJIT 而不是 vanilla Lua 5.1 来解决这个问题。
  • @EgorSkriptunoff 我希望!它也会更快......但是我必须支持香草Lua 5.1。如果我可以通过强制使用我喜欢的 Lua 解释器来解决问题,那么我可以利用很多东西。
  • Lua 作者已经放弃了对 Lua 5.1 的支持。目前,Lua 5.1 中有一些已知的错误,但这些错误永远不会被修复! Lua 团队建议升级你的 Lua。为什么还支持 Lua 5.1?
  • @EgorSkriptunoff 因为它作为预装在某些平台上的默认 Lua 解释器而显得丑陋,这些平台仍然比人们希望的更受欢迎。相信我,我希望情况并非如此,这对我来说是一个痛苦的话题。
  • 顺便说一句,Lua 5.1 中还有另一种语法:a "&lt;" (b),涉及__call 元方法。

标签: lua lua-table


【解决方案1】:

恐怕这是不可能的。如果您比较 5.1 和 5.3 的 luaV_lessthan 的实现可能会有所帮助:

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 函数时,由于在代码中发现 &lt; 而发出该函数,这些实现的作用截然不同。当旧解释器看到不同类型的操作数时,它会很快退出。因此,根本无法将未包装的数字与表格进行比较。

【讨论】:

    猜你喜欢
    • 2020-06-25
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多