14.元表
14.1 知识点
元表的概念
- 任何表变量都可以作为另一个表变量的元表
- 任何表变量都可以有自己的元表
- 一个表的元表可以理解为表的父表 当前表可以理解为元表的子表
- 当我们子表中进行一些特定操作时
- 会执行元表中的内容
设置和得到元表
设置元表方法 setmetatable(子表,元表(父表))
myMetaTable1 = {}
myTable1 = {}
setmetatable(myTable1, myMetaTable1)
得到元表方法 getmetatable(子表)
print(getmetatable(myTable1)) --table: 00B91AF0
print(myMetaTable1) --table: 00B91AF0
元表的__tostring方法 子表当成字符串时用到
- 当子表要被当做字符串使用时 会默认调用子表的元表中的__tostring方法
- 比如直接打印输出表时 就会调用元表中的tostring方法
- 元表的__tostring函数变量可以选择有没有参数
- 没参数的话直接返回字符串即可
- 有参数的话参数默认传的是子表当参数
myMetaTable2 = {
-- 无参函数
-- __tostring = function()
-- return "韬老狮1"
-- end
-- 有参函数
__tostring = function(sonTable)
return sonTable.name
end
}
myTable2 = {
name = "韬老狮2"
}
setmetatable(myTable2, myMetaTable2)
print(myTable2) --韬老狮2 因为是有参函数
-- 如果元表的__tostring使用的是无参函数变量的话就是韬老狮1
-- 如果元表的__tostring为空会打印表信息table: 00CBA480
元表的__call方法 子表当成函数时用到
- 当子表被当做一个函数来使用时 会默认调用子表的元表中的___call方法
- 如果子表被当做一个函数来使用时但子表的元表中的___call方法没有被实现 会报错
myMetaTable3 = {
--__call方法的第一个参数 是元表的子表
__call = function(sonTable, parameter1, parameter2)
print(sonTable) --把子表当做字符串使用 假如当前元表没有__tostring方法就直接打印表变量
print(parameter1)
print(parameter2)
print("韬老狮好爱你")
end
}
myTable3 = {
name = "韬老狮3"
}
setmetatable(myTable3, myMetaTable3)
myTable3("一刀999", "两刀666")
-- table: 00BA2830
-- 一刀999
-- 两刀666
-- 韬老狮好爱你
元表的运算重载方法 子表做运算时用到
- 当子表和别的表做运算符操作时时 会默认调用子表的元表中的一些运算符方法 相当于运算符重载
- 运算符方法第一个参数是当前子表 第二个参数是和子表操作的表
- 注意:子表和别的表使用条件运算符做操作时 子表和别的表要共享同一个元表 即别的表的元表也要设置成当前子表的元表 否则使用条件运算符报错
myMetaTable4 = {
--运算符+
__add = function(table1, table2)
return table1.age + table2.age
end,
--运算符-
__sub = function(table1, table2)
return table1.age - table2.age
end,
--运算符*
__mul = function(table1, table2)
return table1.age * table2.age
end,
--运算符/
__div = function(table1, table2)
return table1.age / table2.age
end,
--运算符%
__mod = function(table1, table2)
return table1.age % table2.age
end,
--运算符^
__pow = function(table1, table2)
return table1.age ^ table2.age
end,
--运算符==
__eq = function(table1, table2)
return table1.age == table2.age
end,
--运算符<
__lt = function(table1, table2)
return table1.age < table2.age
end,
--运算符<=
__le = function(table1, table2)
return table1.age <= table2.age
end,
--运算符..
__concat = function(table1, table2)
return table1.age .. table2.age
end
}
myTable41 = { age = 100 }
setmetatable(myTable41, myMetaTable4)
myTable42 = { age = 10 }
print(myTable41 + myTable42) --110
print(myTable41 - myTable42) --90
print(myTable41 * myTable42) --1000
print(myTable41 / myTable42) --19
print(myTable41 % myTable42) --0
print(myTable41 ^ myTable42) --1e+020
setmetatable(myTable42, myMetaTable4) --为了使用条件运算符比较 两个表的元表必须是同一个表 否则报错
print(myTable41 == myTable42) --false
print(myTable41 > myTable42) --true
print(myTable41 <= myTable42) --false
print(myTable41 .. myTable42) --10010
元表的__index表 子表得到某属性时用到
- 当子表中想得某一个属性 但找不到对应属性时 会到子表的元表中找__index表变量中有没有对应属性
myMetaTable5 = {
__index = { name = "韬老狮5" }
}
myTable5 = {
}
setmetatable(myTable5, myMetaTable5)
print(myTable5.name) --韬老狮5 myTable5中没有name 去myMetaTable5中找到__index指向的表 得到里面的name的值
myMetaTable5.__index = { name = "韬老狮55" } --也可以在外面赋值元表的__index变量
print(myTable5.name) --韬老狮55 myMetaTable5在外面重新设置了__index指向的表
- 注意:有个小坑 假如元表的__index表变量指向的是自己 假如直接在元表内部声明会打印nil
- 所以假如元表的__index指向的是自己建议在外部赋值
myMetaTable6 = {
name = "韬老狮6",
__index = myMetaTable6
}
myTable6 = {
}
setmetatable(myTable6, myMetaTable6)
print(myTable6.name) --nil
myMetaTable6.__index = myMetaTable6 --元表的__index指向的是自己建议在外部赋值
print(myTable6.name) --韬老狮6
- 元表中的__index表变量假如没有对应属性 那么会嵌套的去元表的元表的的__index表变量中找对应属性 还可以一起继续一层一层往上找 直到找不到
myMetaTable7Father = {
name = "韬老狮7",
}
myMetaTable7 = {
}
myTable7 = {
}
setmetatable(myTable7, myMetaTable7)
setmetatable(myMetaTable7, myMetaTable7Father)
myMetaTable7.__index = myMetaTable7 --假如myTable7找不到属性去myMetaTable7的__index表变量找 即myMetaTable7自己
myMetaTable7Father.__index =
myMetaTable7Father --假如myMetaTable7还找不到属性去myMetaTable7Father的__index表变量找 即myMetaTable7Father自己
print(myTable7.name) --韬老狮7
- 不查询元表中的__index表方法 rawget(子表, “要查询的属性”)
- 该方法只会在子表中查找 子表没有就没有了 不会去元表查找__index表了
print(myTable7.name) --韬老狮7 元表的__index表有name属性
print(rawget(myTable7, "name")) --nil 子表没有name属性
myTable7.name = "韬老狮777" --子表设置name属性
print(rawget(myTable7, "name")) --韬老狮777 找到了子表的name属性
print(myTable7.name) --韬老狮7 找到了子表的name属性就不去找元表了
- 元表的 __index 可以是一个函数
- 如果是函数,它会在子表中找不到属性时被调用,并传入两个参数:子表(触发元方法的表)和访问的键。
myMetaTableIndexFunc = {
__index = function(table, key)
if key == "greeting" then
return "Hello from function!"
else
return "Key not found"
end
end
}
myTableIndexFunc = {}
setmetatable(myTableIndexFunc, myMetaTableIndexFunc)
print(myTableIndexFunc.greeting) -- Hello from function!
print(myTableIndexFunc.otherKey) -- Key not found
元表的__newIndex表 子表改某一个属性赋值时用到
- 当子表中想改某一个属性并赋值 但找不到对应属性时 会把这个属性赋值到元表的__newindex所指的表中 不会修改子表
myMetaTable8 = {}
myMetaTable8.__newindex = {}
myTable8 = {}
setmetatable(myTable8, myMetaTable8)
myTable8.name = "韬老狮8" --设置了一个myTable7本来并不存在的属性name
print(myTable8.name) -- nil 因为myTable8的元表myMetaTable8中存在__newindex表变量
print(myMetaTable8.__newindex.name) --韬老狮8 name赋值到元表的__newinde表
- 不修改元表中的__newIndex表方法 rawset(子表, “要设置的属性”, 属性值)
- 该方法只会在子表设置属性 子表没有该属性 不会去元表设置到__newIndex表上了
print(myTable8.age) --nil myTable8现在没有age属性
rawset(myTable8, "age", 22) --设置age属性到子表
print(myMetaTable8.__newindex.age) --nil 元表的__newindex找不到age属性 没有设置到元表的__newindex表中
print(myTable8.age) --22 子表有age属性了
- 元表的 __newindex 也可以是一个函数
- 如果是函数,它会在子表中赋值属性时被调用,并传入三个参数:子表(触发元方法的表)和访问的键和值。
myMetaTableNewIndexFunc = {
__newindex = function(table, key, value)
print("Trying to set " .. key .. " to " .. value)
end
}
myTableNewIndexFunc = {}
setmetatable(myTableNewIndexFunc, myMetaTableNewIndexFunc)
myTableNewIndexFunc.name = "人间自有韬哥在" -- Trying to set name to 人间自有韬哥在
14.2 知识点代码
print("**********元表************")
print("**********知识点一 元表的概念************")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表
--一个表的元表可以理解为表的父表 当前表可以理解为元表的子表
--当我们子表中进行一些特定操作时
--会执行元表中的内容
print("**********知识点二 设置和得到元表************")
--设置元表方法 setmetatable(子表,元表(父表))
myMetaTable1 = {}
myTable1 = {}
setmetatable(myTable1, myMetaTable1)
--得到元表方法 getmetatable(子表)
print(getmetatable(myTable1)) --table: 00B91AF0
print(myMetaTable1) --table: 00B91AF0
print("**********知识点三 元表的__tostring方法************")
--当子表要被当做字符串使用时 会默认调用子表的元表中的__tostring方法
--比如直接打印输出表时 就会调用元表中的tostring方法
--元表的__tostring函数变量可以选择有没有参数
-- 没参数的话直接返回字符串即可
-- 有参数的话参数默认传的是子表当参数
myMetaTable2 = {
-- __tostring = function()
-- return "韬老狮1"
-- end
__tostring = function(sonTable)
return sonTable.name
end
}
myTable2 = {
name = "韬老狮2"
}
setmetatable(myTable2, myMetaTable2)
print(myTable2) --韬老狮2
-- 如果元表的__tostring使用的是无参函数变量的话就是韬老狮1 如果元表的__tostring为空会打印表信息table: 00CBA480
print("**********知识点四 元表的__call方法************")
--当子表被当做一个函数来使用时 会默认调用子表的元表中的___call方法
--如果子表被当做一个函数来使用时但子表的元表中的___call方法没有被实现 会报错
myMetaTable3 = {
--__call方法的第一个参数 是元表的子表
__call = function(sonTable, parameter1, parameter2)
print(sonTable) --把子表当做字符串使用 假如当前元表没有__tostring方法就直接打印表变量
print(parameter1)
print(parameter2)
print("韬老狮好爱你")
end
}
myTable3 = {
name = "韬老狮3"
}
setmetatable(myTable3, myMetaTable3)
myTable3("一刀999", "两刀666")
-- table: 00BA2830
-- 一刀999
-- 两刀666
-- 韬老狮好爱你
print("**********知识点五 元表的运算重载方法************")
--当子表和别的表做运算符操作时时 会默认调用子表的元表中的一些运算符方法 相当于运算符重载
--运算符方法第一个参数是当前子表 第二个参数是和子表操作的表
--注意:子表和别的表使用条件运算符做操作时 子表和别的表要共享同一个元表 即别的表的元表也要设置成当前子表的元表 否则使用条件运算符报错
myMetaTable4 = {
--运算符+
__add = function(table1, table2)
return table1.age + table2.age
end,
--运算符-
__sub = function(table1, table2)
return table1.age - table2.age
end,
--运算符*
__mul = function(table1, table2)
return table1.age * table2.age
end,
--运算符/
__div = function(table1, table2)
return table1.age / table2.age
end,
--运算符%
__mod = function(table1, table2)
return table1.age % table2.age
end,
--运算符^
__pow = function(table1, table2)
return table1.age ^ table2.age
end,
--运算符==
__eq = function(table1, table2)
return table1.age == table2.age
end,
--运算符<
__lt = function(table1, table2)
return table1.age < table2.age
end,
--运算符<=
__le = function(table1, table2)
return table1.age <= table2.age
end,
--运算符..
__concat = function(table1, table2)
return table1.age .. table2.age
end
}
myTable41 = { age = 100 }
setmetatable(myTable41, myMetaTable4)
myTable42 = { age = 10 }
print(myTable41 + myTable42) --110
print(myTable41 - myTable42) --90
print(myTable41 * myTable42) --1000
print(myTable41 / myTable42) --19
print(myTable41 % myTable42) --0
print(myTable41 ^ myTable42) --1e+020
setmetatable(myTable42, myMetaTable4) --为了使用条件运算符比较 两个表的元表必须是同一个表 否则报错
print(myTable41 == myTable42) --false
print(myTable41 > myTable42) --true
print(myTable41 <= myTable42) --false
print(myTable41 .. myTable42) --10010
print("**********知识点六 元表的__index表************")
--当子表中想得某一个属性 但找不到对应属性时 会到子表的元表中找__index表变量中有没有对应属性
myMetaTable5 = {
__index = { name = "韬老狮5" }
}
myTable5 = {
}
setmetatable(myTable5, myMetaTable5)
print(myTable5.name) --韬老狮5 myTable5中没有name 去myMetaTable5中找到__index指向的表 得到里面的name的值
myMetaTable5.__index = { name = "韬老狮55" } --也可以在外面赋值元表的__index变量
print(myTable5.name) --韬老狮55 myMetaTable5在外面重新设置了__index指向的表
--注意:有个小坑 假如元表的__index表变量指向的是自己 假如直接在元表内部声明会打印nil
--所以假如元表的__index指向的是自己建议在外部赋值
myMetaTable6 = {
name = "韬老狮6",
__index = myMetaTable6
}
myTable6 = {
}
setmetatable(myTable6, myMetaTable6)
print(myTable6.name) --nil
myMetaTable6.__index = myMetaTable6 --元表的__index指向的是自己建议在外部赋值
print(myTable6.name) --韬老狮6
--元表中的__index表变量假如没有对应属性 那么会嵌套的去元表的元表的的__index表变量中找对应属性 还可以一起继续一层一层往上找 直到找不到
myMetaTable7Father = {
name = "韬老狮7",
}
myMetaTable7 = {
}
myTable7 = {
}
setmetatable(myTable7, myMetaTable7)
setmetatable(myMetaTable7, myMetaTable7Father)
myMetaTable7.__index = myMetaTable7 --假如myTable7找不到属性去myMetaTable7的__index表变量找 即myMetaTable7自己
myMetaTable7Father.__index =
myMetaTable7Father --假如myMetaTable7还找不到属性去myMetaTable7Father的__index表变量找 即myMetaTable7Father自己
print(myTable7.name) --韬老狮7
--不查询元表中的__index表方法 rawget(子表, "要查询的属性") 该方法只会在子表中查找 子表没有就没有了 不会去元表查找__index表了
print(myTable7.name) --韬老狮7 元表的__index表有name属性
print(rawget(myTable7, "name")) --nil 子表没有name属性
myTable7.name = "韬老狮777" --子表设置name属性
print(rawget(myTable7, "name")) --韬老狮777 找到了子表的name属性
print(myTable7.name) --韬老狮7 找到了子表的name属性就不去找元表了
-- 元表的 __index 可以是一个函数
-- 如果是函数,它会在子表中找不到属性时被调用,并传入两个参数:子表(触发元方法的表)和访问的键。
myMetaTableIndexFunc = {
__index = function(table, key)
if key == "greeting" then
return "Hello from function!"
else
return "Key not found"
end
end
}
myTableIndexFunc = {}
setmetatable(myTableIndexFunc, myMetaTableIndexFunc)
print(myTableIndexFunc.greeting) -- Hello from function!
print(myTableIndexFunc.otherKey) -- Key not found
print("**********知识点七 元表的__newIndex表************")
--当子表中想改某一个属性并赋值 但找不到对应属性时 会把这个属性赋值到元表的__newindex所指的表中 不会修改子表
myMetaTable8 = {}
myMetaTable8.__newindex = {}
myTable8 = {}
setmetatable(myTable8, myMetaTable8)
myTable8.name = "韬老狮8" --设置了一个myTable7本来并不存在的属性name
print(myTable8.name) -- nil 因为myTable8的元表myMetaTable8中存在__newindex表变量
print(myMetaTable8.__newindex.name) --韬老狮8 name赋值到元表的__newinde表
--不修改元表中的__newIndex表方法 rawset(子表, "要设置的属性", 属性值) 该方法只会在子表设置属性 子表没有该属性 不会去元表设置到__newIndex表上了
print(myTable8.age) --nil myTable8现在没有age属性
rawset(myTable8, "age", 22) --设置age属性到子表
print(myMetaTable8.__newindex.age) --nil 元表的__newindex找不到age属性 没有设置到元表的__newindex表中
print(myTable8.age) --22 子表有age属性了
-- 元表的 __newindex 也可以是一个函数
-- 如果是函数,它会在子表中赋值属性时被调用,并传入三个参数:子表(触发元方法的表)和访问的键和值。
myMetaTableNewIndexFunc = {
__newindex = function(table, key, value)
print("Trying to set " .. key .. " to " .. value)
end
}
myTableNewIndexFunc = {}
setmetatable(myTableNewIndexFunc, myMetaTableNewIndexFunc)
myTableNewIndexFunc.name = "人间自有韬哥在" -- Trying to set name to 人间自有韬哥在
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com