6.元表*
元表的概念
实现面向对象的重要结构
- 任何表变量都可以作为另一个表变量的元表
- 任何变量都可以有自己的元表(father)
- 子表执行一些特殊操作的时候会调用元表的内容
设置元表
print("**********元表************")
print("**********元表概念************")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(爸爸)
--当我们子表中进行一些特定操作时
--会执行元表中的内容
print("**********设置元表************")
meta = {}
myTable = {}
--设置元表函数
--第一个参数 子表
--第二个参数 元表(爸爸)
setmetatable(myTable, meta)特定操作
除__tostring外(默认为内存地址),其他特定操作需要给子表设置元表后才会有,如果直接声明一个表就去调用会报错
__tostring
调用子表的tostring会默认把子表传到元表的__tostring,并可以调用子表的属性(表被当作字符串调用的时候)
print("**********特定操作************")
print("**********特定操作-__tostring************")
meta2 = {
--当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end
}
myTable2 = {
name = "ColdPlay"
}
--设置元表函数
--第一个参数 子表
--第二个参数 元表(father)
setmetatable(myTable2, meta2)
print(myTable2)输出:
**********特定操作-__tostring************
ColdPlay
__tocall
同上,子表被当作函数调用的时候会调用元表的__call
- 当希望传递参数的时候,默认的第一个参数为调用者自己
print("**********特定操作-__call************")
meta3 = {
--当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end,
--当子表被当做一个函数来使用时 会默认调用这个__call中的内容
--当希望传参数时 一定要记住 默认第一个参数 是调用者自己
__call = function(a, b)
print(a)
print(b)
print("小海豚")
end
}
myTable3 = {
name = "HotPlay"
}
--设置元表函数
--第一个参数 子表
--第二个参数 元表(father)
setmetatable(myTable3, meta3)
--把子表当做函数使用 就会调用元表的 __call方法
myTable3(1)输出:
**********特定操作-__call************
HotPlay
1
小海豚运算符重载
对子表进行运算符操作的时候,会调用元表重载的运算符方法
- 没有>、>=、~=的重载(调用的时候会取反)
- 使用条件运算符比较两个表的时候,这两个表的元表要一致
print("**********特定操作-运算符重载************")
meta4 = {
--相当于运算符重载 当子表使用+运算符时 会调用该方法
--运算符+
__add = function(t1, t2)
return t1.age + t2.age
end,
--运算符-
__sub = function(t1, t2)
return t1.age - t2.age
end,
--运算符*
__mul = function(t1, t2)
return 1
end,
--运算符/
__div = function(t1, t2)
return 2
end,
--运算符%
__mod = function(t1, t2)
return 3
end,
--运算符^
__pow = function(t1, t2)
return 4
end,
--运算符==
__eq = function(t1, t2)
return true
end,
--运算符<
__lt = function(t1, t2)
return true
end,
--运算符<=
__le = function(t1, t2)
return false
end,
--运算符..
__concat = function(t1, t2)
return "567"
end
}
myTable4 = {age = 1}
setmetatable(myTable4, meta4)
myTable5 = {age = 2}
setmetatable(myTable5, meta4)
print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)
--如果要用条件运算符 来比较两个对象
--这两个对象的元表一定要一致 才能准确调用方法
print(myTable4 == myTable5)
print(myTable4 > myTable5)
print(myTable4 <= myTable5)
print(myTable4 .. myTable5)输出:
**********特定操作-运算符重载************
3
-1
1
2
3
4
true
true
false
567__index和__newIndex*
__index
-
当在子表中找不到一个元素时,会去元表__index指定的表去找对应的索引
注意:
meta6={
age=1,
__index=mete6
}
-- 建议使用 meta6.__index=meta6 写在外部
Table6={}
setmetatable(Table6,meta6)
-- 会输出nil
print(Table6.age)- __index可以不断向上寻找,既当在表中找不到某个元素,会去该表的元表index指向的表寻找,如果依旧找不到,会继续向上寻找
__newIndex
- 当赋值的时候,如果赋值到一个不存在的索引,就会把这个值赋到__newIndex指向的表,同样具有向上寻找的特性
-
注意,当指定了newIndex,新增的元素,会被设置到newindex指向的表,而非当前使用的表,可以使用rewset忽略newindex的存在
--newIndex 当赋值时,如果赋值一个不存在的索引
--那么会把这个值赋值到newindex所指的表中 不会修改自己
meta7 = {}
meta7.__newindex = {}
myTable7 = {}
setmetatable(myTable7, meta7)
myTable7.age = 1
print(myTable7.age)
输出:
nil- 如果不设置__newIndex,那么就会设置到当前操作表本身
meta11={}
table11={}
setmetatable(table11,meta11)
table11.age=11
print(table11.age)输出
11其他
-- 得到元表的方法 调用__tostring,默认为内存地址
print(getmetatable(myTable6))
--rawget 当我们使用它是 会去找自己身上有没有这个变量(忽略__index)
--myTable6.age = 1
print(rawget(myTable6, "age"))
--rawset 该方法 会忽略__newindex的设置 只会该自己的变量
rawset(myTable7, "age", 2)
print(myTable7.age)
输出:
table: 00A62CA0
1
2
这篇文章主要介绍了Lua语言中的元表(metatable)概念及其应用。元表是实现面向对象编程的重要结构,允许一个表作为另一个表的元表(类似父类)。文章详细讲解了如何设置元表,以及几种特殊的元表操作:
- __tostring:当子表被当作字符串使用时调用
- __call:当子表被当作函数调用时触发
- 运算符重载:通过定义__add、__sub等方法重载运算符
- __index和__newindex:控制表中不存在的键的访问和赋值行为
特别强调了: - 除__tostring外,其他操作需要显式设置元表
- 条件运算符比较时需要两个表有相同的元表
- __index用于查找不存在的键,__newindex用于拦截对新键的赋值
文章通过多个代码示例演示了这些特性的具体用法,包括字符串转换、函数调用、各种运算符重载的实现方式等。
