MetaTable and MetaMethod
比如,我们有两个分数:
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">"Attempt to 'add' a set with a not-set value"</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)
参考链接: