算术运算的元方法 Metamethods

Posted 森明帮大于黑虎帮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算术运算的元方法 Metamethods相关的知识,希望对你有一定的参考价值。

这一部分我们通过一个简单的例子介绍如何使用 metamethods。假定我们使用 table来描述结合,使用函数来描述集合的并操作,交集操作, like 操作。我们在一个表内定义这些函数,然后使用构造函数创建一个集合:

为了帮助理解程序运行结果,我们也定义了打印函数输出结果:

现在我们想加号运算符(+)执行两个集合的并操作,我们将所有集合共享一个metatable,并且为这个 metatable 添加如何处理相加操作。

第一步,我们定义一个普通的表,用来作为 metatable。为避免污染命名空间,我们将其放在 set 内部。

Set.mt =  -- metatable for sets

第二步,修改 set.new 函数,增加一行,创建表的时候同时指定对应的 metatable

function Set.new (t) -- 2nd version
local set = 
setmetatable(set, Set.mt)
for _, l in ipairs(t) do set[l] = true end
return set
end

这样一来, set.new 创建的所有的集合都有相同的 metatable 了:

下图可知s1和s2的元表相同。

第三步,给 metatable 增加__add 函数。

Lua 试图对两个集合相加时,将调用这个函数,以两个相加的表作为参数。通过 metamethod,我们可以对两个集合进行相加:

同样的我们可以使用相乘运算符来定义集合的交集操作:

结果如下:

对于每一个算术运算符, metatable 都有对应的域名与其对应,除了__add、 __mul外,还有__sub(减)、 __div(除)、 __unm(负)、 __pow(幂),我们也可以定义__concat 定义连接行为。

当我们对两个表进行加没有问题,但如果两个操作数有不同的 metatable 例如:

Lua 选择 metamethod 的原则:如果第一个参数存在带有__add 域的 metatableLua使用它作为 metamethod,和第二个参数无关;

否则第二个参数存在带有__add 域的 metatableLua 使用它作为 metamethod 否则报错。

Lua 不关心这种混合类型的,如果我们运行上面的 s=s+8 的例子在 Set.union 发生错误:

C:\\Users\\Administrator\\.vscode\\extensions\\actboy168.lua-debug-1.59.0\\runtime\\win32-x64\\lua54\\lua.exe: ...ments\\Tencent Files\\1978045947\\FileRecv\\Lua代码/main.lua:2593: attempt to 'add' a set with a non-set value
stack traceback:
        [C]: in function 'error'
        ...ments\\Tencent Files\\1978045947\\FileRecv\\Lua代码/main.lua:2542: in metamethod 'add'
        ...ments\\Tencent Files\\1978045947\\FileRecv\\Lua代码/main.lua:2593: in main chunk
        [C]: in ?

如果我们想得到更加清楚地错误信息,我们需要自己显式的检查操作数的类型:

function Set.union (a,b)
if getmetatable(a) ~= Set.mt or
getmetatable(b) ~= Set.mt then
error("attempt to `add' a set with a non-set value", 2)
end
... -- same as before

以上是关于算术运算的元方法 Metamethods的主要内容,如果未能解决你的问题,请参考以下文章

关系运算的元方法(Metamethods)

JavaScript基础之算术运算符 前后增量/前后减量运算符 比较运算符逻辑运算符 程序流程控制

JavaScrpt算术运算符

求Lua 的元表的算术类的元方法例子(加、减、乘、除等等) ,详细的例子

算术运算符

在python中有多少种运算符?解释一下算术运算符