6.元表*

image

元表的概念

实现面向对象的重要结构

  • 任何表变量都可以作为另一个表变量的元表
  • 任何变量都可以有自己的元表(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)概念及其应用。元表是实现面向对象编程的重要结构,允许一个表作为另一个表的元表(类似父类)。文章详细讲解了如何设置元表,以及几种特殊的元表操作:

  1. __tostring:当子表被当作字符串使用时调用
  2. __call:当子表被当作函数调用时触发
  3. 运算符重载:通过定义__add、__sub等方法重载运算符
  4. __index和__newindex:控制表中不存在的键的访问和赋值行为
    特别强调了:
  5. 除__tostring外,其他操作需要显式设置元表
  6. 条件运算符比较时需要两个表有相同的元表
  7. __index用于查找不存在的键,__newindex用于拦截对新键的赋值
    文章通过多个代码示例演示了这些特性的具体用法,包括字符串转换、函数调用、各种运算符重载的实现方式等。
最后修改:2025 年 06 月 05 日
如果觉得我的文章对你有用,请随意赞赏