Lua 学习笔记(6)元表(metatable)与元方法(metamethod)
《Lua程序设计》
Lua中每个值都有一套预定义的操作集合。例如数字的相加,字符串的连接。当Lua要把两个表相加时,会检查元表是否有个叫__add的字段,有的话就调用(即 元方法)。
local mt = {}
MyTable = {}
function MyTable.new(l)
local set = {}
setmetatable(set, mt)
for _, v in ipairs(l) do set[v] = true end
return set
end
function MyTable.union(a,b)
local res = {}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
function MyTable.tostring(t)
local l = {}
for e in pairs(t) do
l[#l + 1] = e
end
return "{" .. table.concat(l, ", ").. "}"
end
function MyTable.print(s)
print(MyTable.tostring(s))
end
local t1 = MyTable.new{1,2,3} -- 元表格式创建
local t2 = setmetatable({[1] = true,[4] = true},mt) --匿名格式创建
mt.__add = MyTable.union -- 相当于重载‘+’运算符
MyTable.print(t1) --> {1, 2, 3}
MyTable.print(t2) --> {4, 1}
MyTable.print(t1 + t2) --> {1, 2, 3, 4}
local t3 = MyTable.new{1,2}
t3 = t3 + 8 --如果第一个值有元表且有__add,用第一个值的元方法,否则用第二个,如果两个都没元方法,报错。
算术类型
- __add:加法
- __mul:乘法
- __sub:减法
- __div:除法
- __unm: 相反数
- __mod:取模
- __pow:乘幂
- __concat:连接操作
关系类型
- __eq:等于。两个对象拥有不同元方法时,等于操作会直接返回false
- __lt:小于
- __le:小于等于
NAN: Not a Number,未定义的值。
库定义的元方法
- __tostring:转换成字符串
- __metatable:如果设置了该字段,调用getmetatable就会返回这个字段的内容,调用setmetatable就会引发一个报错(cannot change protected metatable)。
__index元方法
- table访问字段时,如果访问不到,会调用__index元方法。用于table的查询。
- 使用
rawget
方法可以绕过元方法。
Window = {}
Window.prototype = {x = 0,y = 0, width = 100, height = 100}
Window.mt = {}
function Window.new(o)
setmetatable(o, Window.mt)
return o
end
Window.mt.__index = function(table, key)
return Window.prototype[key]
end
w = Window.new{x = 10, y = 20}
print(w.x) --> 10
print(w.width) --> 100
print(w.z) --> nil
__newindex
-
用于table的更新,即对table不存在的值赋值时,就会调用__newindex元方法。
-
使用
rawset
方法可以绕过元方法。
具有默认值的table
function setDefault(t, d)
local mt = {__index = function() return d end}
setmetatable(t, mt)
end
tab = {x = 10, y = 20}
print(tab.x, tab.z) --> 10 nil
setDefault(tab, 0)
print(tab.x, tab.z) --> 10 0