local mt = {} -- 创建元表
local t = {a=1, b=2} -- 创建主体表
-- 尝试获取元表
local mt_got = getmetatable(t)
if mt_got == nil then
print("The table does not have a metatable.")
else
print("The table has a metatable.")
end
--输出 The table does not have a metatable.
setmetatable(t, mt) -- 设置主体表的元表
local t = {a=1, b=2}
-- 尝试获取元表
local mt_got = getmetatable(t)
if mt_got == nil then
print("The table does not have a metatable.")
else
print("The table has a metatable.")
end
--输出 The table has a metatable.
讲到元方法就必须得提__index
函数调用会返回函数的返回值(table表和key索引值会作为参数传递进去)
-- MetatableTest.lua
local mt = {
__index = function (t, key)
print("正在寻找 "..key.."是否在元表里")
if key == 'specialKey' then
return "关键值"
else
return "未知值"
end
end
}
local t = {a=1, b=2}
setmetatable(t, mt)
print("t.specialKey:"..t.specialKey) -- 输出:正在寻找 "..specialKey.."是否在元表里
-- t.specialKey:关键值
print("t.C:"..t.C) -- 输出: 正在寻找 C是否在元表里
-- t.C:未知值
print("t.a:"..t.a) -- 输出: t.a:1
-- MetatableTest.lua
local mt = {
__index = { c = 3, d = 4 } -- 设置 __index 为一个包含键值对的新表
}
local t = {a=1, b=2,'a','b','c'}
setmetatable(t, mt)
-- 检查元表设置是否成功
print(getmetatable(t)) -- 应该输出: table: 地址
print(t.a) -- 输出: 1
print(table.concat(t, '|')) -- 输出 a|b|c
print(t.c) -- 输出: 3
print(t.d) -- 输出: 4
print(t.e) -- 输出: nil
-- MetatableTest.lua
local mt = {
__index = { c = 3, d = 4 }, -- 设置 __index 为一个包含键值对的新表
__newindex = function(t, key, value)
print("Setting key ", key, " to value ", value)
rawset(t, key, value) -- 使用 rawset 直接设置到表中
end
}
local t = {a=1, b=2, 'a', 'b', 'c'}
setmetatable(t, mt)
-- 检查元表设置是否成功
print(getmetatable(t)) -- 应该输出: table: 地址
print(table.concat(t, '|')) -- 输出: a|b|c
print(t.c) -- 应该输出: 3
print(t.d) -- 应该输出: 4
print(t.e) -- 应该输出: nil
-- 使用 __newindex
t.newkey = "newvalue" -- 触发 __newindex
-- 使用 rawset
rawset(t, 'anotherkey', "anothervalue") -- 不触发 __newindex
-- 显示所有键值对
for k, v in pairs(t) do
print(k..'|'..v)
end
local readonl1yTable = setmetatable({}, {
__newindex = function(tbl, key, value)
error("Attempt to modify a read-only table")
end
})
-- 尝试修改只读表
readonlyTable.someKey = "someValue" -- 这里会抛出错误
在这个例子中,当我们尝试向 readonlyTable 添加一个新键或更新一个已存在的键时,Lua 会调用元表中的 __newindex 方法。由于我们定义了这个方法来抛出一个错误,因此任何对 readonlyTable 的修改都会失败,并抛出一个错误信息。
元表中有一些类似于CPP重载运算符的操作
当调用相应的运算符时会根据对应模式域触发相应的事件
模式 | 描述 |
---|---|
add | 对应的运算符 '+' |
sub | 对应的运算符 '-' |
mul | 对应的运算符 '*' |
div | 对应的运算符 '/' |
mod | 对应的运算符 '%' |
unm | 对应的运算符 '-' |
concat | 对应的运算符 '..' |
eq | 对应的运算符 '==' |
lt | 对应的运算符 '<' |
le | 对应的运算符 '<=' |
以__add为例
-- MetatableTest.lua
-- 因为table_maxn在lua5.2以后废弃了所以需要自己实现
-- 自定义计算表中最大键值函数 table_maxn,即返回表最大键值
function table_maxn(t)
local mn = 0
for k, _ in pairs(t) do
if type(k) == "number" and k > mn then
mn = k
end
end
return mn
end
-- __add 两表元素相加操作
print("--------------------------------------------------")
local mytable1 = setmetatable({1, 2, 3}, {
__add = function(mytable, newtable)
local max_key_mytable = table_maxn(mytable)
for i = 1, table_maxn(newtable) do
table.insert(mytable, max_key_mytable + i, newtable[i])
end
return mytable
end
})
local secondtable1 = {4, 5, 6}
mytable1 = mytable1 + secondtable1
print("After adding tables:")
for k, v in ipairs(mytable1) do
print(k.."|"..v)
end
-- __add 表里的两个数值相加操作
print("--------------------------------------------------")
local mytable2 = setmetatable({1, 2, 3}, {
__add = function(mytable, newtable)
local max_len = math.min(#mytable, #newtable)
for i = 1, max_len do
mytable[i] = mytable[i] + newtable[i]
end
return mytable
end
})
local secondtable2 = {4, 5, 6}
mytable2 = mytable2 + secondtable2
print("After adding values:")
for k, v in ipairs(mytable2) do
print(k.."|"..v)
end
__tostring 元方法用于控制如何将一个对象转换为字符串。当将一个对象转换成字符串时(例如,使用 tostring 函数或在 print 函数中打印一个对象),如果对象的元表中定义了 __tostring 元方法,那么这个元方法将被调用。
-- MetatableTest.lua
-- __tostring 函数
print("--------------------------------------------------")
mytable = setmetatable({ 10, 20, 30 }, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "表所有元素的和为 " .. sum
end
})
print(mytable) -- 输出表所有元素和为 60
__call 元方法用于控制如何将一个对象当作函数来调用。当你尝试将一个对象当作函数调用时(例如,使用 obj(arg1, arg2) 的形式),如果对象的元表中定义了\ __call 元方法,那么这个元方法将被调用。调用这个元方法时, func 作为第一个参数传入,原来调用的参数(args)后依次排在后面。
-- MetatableTest.lua
-- 自定义计算表中最大键值函数 table_maxn,即返回表最大键值
function table_maxn(t)
local mn = 0
for k, _ in pairs(t) do
if type(k) == "number" and k > mn then
mn = k
end
end
return mn
end
-- 定义元方法 __call
local mytable = setmetatable({10}, {
__call = function(mytable, newtable)
local sum = 0
for i = 1, table_maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1, table_maxn(newtable) do
sum = sum + newtable[i]
end
return "两个表所有元素和为"..sum
end
})
local newtable = {10, 20, 30}
print(mytable(newtable)) --输出 "两个表所有元素和为70"
元表定义了值在某些特定操作下的行为,根据行为域执行特定的元方法。
元表和元方法是Lua语言中强大的工具,能够帮助开发者实现更复杂的功能,并且提高代码的灵活性和可维护性。理解并正确使用元表可以使Lua程序更加健壮和高效。然而,过度使用或不恰当的使用元表可能会导致难以调试的问题,因此使用时需谨慎。
参考文章:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。