MetaTable and MetaMethod

4.9k 词

比如,我们有两个分数:

fraction_a = {numerator=2, denominator=3}
fraction_b = {numerator=4, denominator=7}

我们想实现分数间的相加:2/3 + 4/7,我们如果要执行: fraction_a + fraction_b,会报错的。

所以,我们可以动用MetaTable,如下所示:

fraction_op={}
function fraction_op.__add(f1, f2)
    ret = {}
    ret.numerator = f1.numerator * f2.denominator + f2.numerator * f1.denominator
    ret.denominator = f1.denominator * f2.denominator
    return ret
end

为之前定义的两个table设置MetaTable:(其中的setmetatble是库函数)

setmetatable(fraction_a, fraction_op)
setmetatable(fraction_b, fraction_op)

于是你就可以这样干了:(调用的是fraction_op.__add()函数)

fraction_s = fraction_a + fraction_b

至于__add这是MetaMethod,这是Lua内建约定的,其它的还有如下的MetaMethod:

__add(a, b)                     对应表达式 a + b
__sub(a, b)                     对应表达式 a - b
__mul(a, b)                     对应表达式 a * b
__div(a, b)                     对应表达式 a / b
__mod(a, b)                     对应表达式 a % b
__pow(a, b)                     对应表达式 a ^ b
__unm(a)                        对应表达式 -a
__concat(a, b)                  对应表达式 a .. b
__len(a)                        对应表达式 #a
__eq(a, b)                      对应表达式 a == b
__lt(a, b)                      对应表达式 a < b
__le(a, b)                      对应表达式 a <= b
__index(a, b)                   对应表达式 a.b
__newindex(a, b, c)             对应表达式 a.b = c
__call(a, ...)                  对应表达式 a(...)
Set = {}
Set.mt = {} -- metatable for sets

function Set.new(t)
t = t or {}
local set = {}
setmetatable(set, Set.mt)
for _, l in ipairs(t) do
set[l] = true
end
return set
end

function Set.union(a, b)

<span class="k">if</span> <span class="nb">getmetatable</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">~=</span> <span class="n">Set</span><span class="p">.</span><span class="n">mt</span> <span class="ow">or</span>
    <span class="nb">getmetatable</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">~=</span> <span class="n">Set</span><span class="p">.</span><span class="n">mt</span> <span class="k">then</span>
    <span class="nb">error</span><span class="p">(</span><span class="s2">&#34;Attempt to &#39;add&#39; a set with a not-set value&#34;</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="k">end</span>

<span class="kd">local</span> <span class="n">res</span> <span class="o">=</span> <span class="n">Set</span><span class="p">.</span><span class="n">new</span><span class="p">()</span>
<span class="k">for</span> <span class="n">k</span> <span class="k">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">res</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span>
<span class="k">end</span>
<span class="k">for</span> <span class="n">k</span> <span class="k">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">res</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="kc">true</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">res</span>

end

function Set.intersection(a, b)
local res = Set.new()
for k in pairs(a) do
res[k] = b[k]
end
return res
end

function Set.tostring(set)
set = set or {}
local s = "{"
local sep = ""
for e in pairs(set) do
s = s sep e
sep = ", "
end
return s "}"
end

function Set.print(s)
print(Set.tostring(s))
end

– 相加
Set.mt.__add = Set.union

– 相乘,交集
Set.mt.__mul = Set.intersection

s1 = Set.new({10, 20, 30, 50})
s2 = Set.new({30, 1})
print(getmetatable(s1))
print(getmetatable(s2))

Set.print(s1)
Set.print(s2)

s3 = s1 + s2
Set.print(s3)

s = Set.new({1, 2, 3})
– s = s + 8 – table加上一个数字

Set.print(s1 * s2)

print("--------------")

print(s1)
print(s2)
– print会自动调用__tostring,我们在这里修改了__tostring
Set.mt.__tostring = Set.tostring
print(s1)
print(s2)

参考链接:

http://coolshell.cn/articles/10739.html

http://book.luaer.cn/