这一部分我们通过一个简单的例子介绍如何使用 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
域的 metatable
, Lua
使用它作为 metamethod
,和第二个参数无关;
否则第二个参数存在带有__add
域的 metatable
, Lua
使用它作为 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
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_44918090/article/details/126259957
内容来源于网络,如有侵权,请联系作者删除!