Lua:元表(metatable)与元方法(meatmethod)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Lua:元表(metatable)与元⽅法(meatmethod)
元表概念:
引⾔:Lua中的每个值都有⼀套预定义的操作集合,如数字相加等。
但⽆法将两个table相加,此时可通过元表修改⼀个值的⾏为,使其在⾯对⼀个⾮预定义的操作时执⾏⼀个指定操作。
访问机制:⼀般的元⽅法都只针对Lua的核⼼,也就是⼀个虚拟机。
它会检测⼀个操作中的值是否有元表,这些元表是否定义了关于次操作的元⽅法。
例如两个table相加,先检查两者之⼀是否有元表,之后检查是否有⼀个叫“__add”的字段,若找到,则调⽤对应的值。
“__add”等即时字段,其对应的值(往往是⼀个函数或是table)就是“元⽅法”。
元表实例
setmetatable(只能⽤于table)和getmetatable(⽤于任何对象)
语法:setmetatable (table, metatable),对指定table设置metatable 【如果元表(metatable)中存在__metatable键值,setmetatable会失败】
语法:tmeta = getmetatable (tab),返回对象的元表(metatable) 【如果元表(metatable)中存在__metatable键值,当返回__metatable的
值】
代码:
print(getmetatable("lua")) -->table: 002F19B8
print(getmetatable(10)) -->nil
--使⽤__metatable可以保护元表,禁⽌⽤户访问元表中的成员或者修改元表。
tA = {}
mt = {}
getmetatable(tA, mt)
mt.__metatable = "lock"
setmetatable(tA, mt)
print(getmetatable(tA)) -->lock
算术类元⽅法: 字段:__add __mul __ sub __div __unm __mod __pow (__concat)
代码:(两个table相加)
tA = {1, 3}
tB = {5, 7}
--tSum = tA + tB
mt = {}
mt.__add = function(t1, t2)
for _, item in ipairs(t2) do
table.insert(t1, item)
end
return t1
end
setmetatable(tA, mt)
tSum = tA + tB
for k, v in pairs(tSum) do
print(v)
end
关系类元⽅法:字段:__eq __lt(<) __le(<=),其他Lua⾃动转换 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a 【注意NaN的情况】
代码:
--⽐较集合⼤⼩ <
mt = {}
function mt.__lt(tA, tB)
return #tA < #tB
end
tA, tB = {3}, {1, 2}
setmetatable(tA, mt)
setmetatable(tB, mt)
print(tA < tB)
table访问的元⽅法:字段: __index __newindex
__index:
查询:访问表中不存的字段
rawget(t, i)
__newindex:
更新:向表中不存在索引赋值
rawswt(t, k, v)
贯穿《Programming in Lua》元表与元⽅法整张的实例
--[[
Set = {}
mt = {} --元表
function Set.new(l)
local set = {}
setmetatable(set, mt)
for _, v in ipairs(l) do
set[v] = true
end
return set
end
--================================================
function Set.tostring(set)
local l = {}
for e in pairs(set) do
l[#l + 1] = e
end
return "{" .. table.concat(l, ",") .. "}"
end
function Set.print(s)
print(Set.tostring(s))
end
--1 加(__add), 并集===============================
function Set.union(a, b)
--[[ if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
error("attemp to 'add' a set with a non-set value", 2) --error第⼆个参数的含义P116 end]]
local res = Set.new{}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
s1 = Set.new{10, 20, 30, 50}
s2 = Set.new{30, 1}
--print(getmetatable(s1))
--print(getmetatable(s2))
mt.__add = Set.union
s3 = s1 + s2
--Set.print(s3)
--[[元表混⽤
s = Set.new{1, 2, 3}
s = s + 8
Set.print(s + 8)
]]
--2 乘(__mul), 交集==============================
function Set.intersection(a, b)
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end
mt.__mul = Set.intersection
--Set.print(s2 * s1)
--3 关系类===================================NaN的概念====
mt.__le = function(a, b)
for k in pairs(a) do
if not b[k] then return false end
end
return true
end
mt.__lt = function(a, b)
return a <= b and not (b <= a)
end
mt.__eq = function(a, b) --竟然能这么⽤!?----
return a <= b and b <= a
end
g1 = Set.new{2, 4, 3}
g2 = Set.new{4, 10, 2}
print(g1 <= g2)
print(g1 < g2)
print(g1 >= g2)
print(g1 > g2)
print(g1 == g1 * g2)
--]]
--============================================
--4 table访问的元⽅法=========================
--[[
--__index有关继承的典型⽰例
Window = {}
Window.prototype = {x = 0, y = 0, width = 100, height} 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.width)
--__index修改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)
setDefault(tab, 0)
print(tab.x, tab.z)
--]]
--13.4.5 只读的table
function readOnly(t)
local proxy = {}
local mt = {
__index = t,
__newindex = function(t, k, v)
error("attempt to update a read-only table", 2)
end
}
setmetatable(proxy, mt)
return proxy
end
days = readOnly{"Sunday", "Monday", "Tuesday", "W", "T", "F", "S"} print(days[1])
days[2] = "Noday"。