元表的介绍
在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。例如,使用元表我们可以定义 Lua 如何计算两个 table 的相加操作 a+b。当 Lua 试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫 __add 的字段,若找到,则调用对应的值。 __add 等即时字段,其对应的值(往往是一个函数或是 table)就是"元方法"
设置元表
setmetatable(table,metatable):
对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table):
返回对象的元表(metatable)。
-- 设置方式 1
mytable = {
} -- 普通表
mymetatable = {
} -- 元表
setmetatable(mytable, mymetatable) -- 把 mymetatable 设为 mytable 的元表
-- 设置方式 2
mytable2 = setmetatable({
}, {
})
--此时元表为匿名状态,想要获取需要使用
print(getmetatable(mytable2)) -- > table
元方法
__tostring 和 __call 重载
__tostring
当被当做字符串使用时,调用__tostring
__call
当子表被当作一个函数使用时,调用__call
-- __tostring 和 __call
meta = {
-- 当被当做字符串使用时,调用__tostring
__tostring = function(t) -- 默认把自己当第一个参数传进来
return t.str
-- return "mmm"
end,
-- 当子表被当作一个函数使用时,调用__call
__call = function(a, b)
print("hello", a, b) -- a 还是自己本身,b才是传的参数
end
}
table = {
str = "nnn"}
setmetatable(table, meta)
print(table) -- > 此时table被当成 string nnn
table("123"); -- > 此时table被当成 function hello nnn 123
输出结果
__add等运算符重载
运算符重载 当把表进行对应的计算时可以重写运算函数
模式 | 描述 |
---|---|
__add | 对应的运算符 ‘+’. |
__sub | 对应的运算符 ‘-’. |
__mul | 对应的运算符 ‘*’. |
__div | 对应的运算符 ‘/’. |
__mod | 对应的运算符 ‘%’. |
__unm | 对应的运算符 ‘-’. |
__concat | 对应的运算符 ‘…’. |
__eq | 对应的运算符 ‘==’. |
__lt | 对应的运算符 ‘<’. |
__le | 对应的运算符 ‘<=’. |
使用示例: + - ==
-- 运算符重载 当把表进行对应的计算时可以重写运算函数
meta2 = {
__add = function(a, b)
return a.age + b.age
end,
__sub = function(a, b)
return a.age - b.age
end,
__eq = function(a, b)
return a.age == b.age
end
}
tableA = {
age = 1}
setmetatable(tableA, meta2)
tableB = {
age = 3}
print(tableA + tableB) -- > 4
print(tableA - tableB) -- > -2
print(tableA == tableB) -- > true
输出结果
__index 和 _newindex
__index
当找不到对应属性时 找元表设置的__index所指向的表
rawget()
忽略__index
meta3 = {
}
table3 = {
}
table4 = {
age = 3}
setmetatable(table3, meta3)
print(table3.age) -- > nil
meta3.__index = {
age = 4} -- 设置 __index
print(table3.age) -- > 4
meta3.__index = table4 -- 设置 __index表为 table4
print(table3.age) -- > 3
print(rawget(table3, "age")) -- > nil
-- __index 还可以套用
meta4 = {
name = "111"}
meta4.__index = meta4
setmetatable(table4, meta4)
print(table3.name) -- > 111
输出结果
__newindex
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作
rawset()
忽略__newindex
meta5 = {
}
meta5.__newindex = {
}
table5 = {
}
setmetatable(table5, meta5)
table5.age = 1 -- 实际上这时改掉的时 元表 __newindex 里的age
print(table5.age) -- > nil
print(meta5.__newindex.age) -- > 1
-- 使用rawset() 就不会设置到__newindex上去了
rawset(table5, "age", 2)
print(table5.age) -- > 2
-- __newindex也是一层层往上找
输出结果
其他元方法
模式 | 描述 |
---|---|
__idiv | the floor division (//) operation. Behavior similar to the addition operation. |
__band | the bitwise AND (&) operation. Behavior similar to the addition operation, except that Lua will try a metamethod if any operand is neither an integer nor a float coercible to an integer (see §3.4.3) |
__bor | the bitwise OR ( |
__bxor | the bitwise exclusive OR (binary ~) operation. Behavior similar to the bitwise AND operation. |
__bnot | the bitwise NOT (unary ~) operation. Behavior similar to the bitwise AND operation. |
__shl | the bitwise left shift (<<) operation. Behavior similar to the bitwise AND operation. |
__shr | the bitwise right shift (>>) operation. Behavior similar to the bitwise AND operation. |
__len | the length () operation. If the object is not a string, Lua will try its metamethod. If there is a metamethod, Lua calls it with the object as argument, and the result of the call (always adjusted to one value) is the result of the operation. If there is no metamethod but the object is a table, then Lua uses the table length operation (see §3.4.7). Otherwise, Lua raises an error. # |
END
参考链接 http://www.lua.org/manual/5.4/manual.html
参考链接 https://www.runoob.com/lua/lua-metatables.html