Lua 表与元表的理解

本文详细讲解了Lua中的表结构,包括赋值、遍历方法,以及元表的概念和关键字段如__index和__newindex的作用。此外,还介绍了如何通过__add等二元操作符重载表的运算行为,以及__call和__tostring字段的应用。适合深入理解Lua表的开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


个人学习笔记,如果有误请留言讨论

概念

Lua的表可以理解为一种类似哈希表的数据结构,使用键值对来存储元素,当不指定某个值的key时,table会把其当作数组元素处理,数组元素在表中键为1, 2, 3…,注意这里数组是从1开始的而非0 。

赋值

这样可以简单地为表赋初值:

table1 = {1, 2, 3}
table2 = {["w"] = "foo", ["a"] = "bar", ["o"] = "ha"}

注意:
在赋初值的时候,表遵循先为键值对创建空间,再为数组创建空间的原则,也就是说如果键值对的键与数组的键重合了,会被覆盖掉。

-- 表中元素为fooArray和bar
local table = {"fooArray", ["1"] = "bar", [1] = "fooHash"}

遍历

常见的有pairs和ipairs两种方法:

  • pairs会遍历表中所有不为空的值。
  • 而ipairs前的i意为int,其会像遍历数组一样,从下标1开始遍历,中间遇到nil值就会停止遍历。
    例子:
local table = {[0] = 0, 1, 2, nil, 4}
for _, v in pairs(table) do
    print(v) -- 1 2 4 0
end
print("----------")
for _, v in ipairs(table) do
    print(v) -- 1 2
end

元表

概念

元表是一种与特定表相关联,描述/改变关联表的行为的表,这里的行为包含访问、插入、加减乘除等,可以理解为重载。
通过给元表的特殊字段赋值来实现上述重载。

设置/获取关联

table = {}
metaTable = {}
setmetatable(table, metaTable) -- 将metaTable设置为table的元表
tmpMetaTable = getmetatable(table) -- 获取table的元表

__index字段和__newindex字段

__index字段规定了在表中查找一个不存在的key时的行为,既可以是一个表也可以是一个函数,如果是表的话会在__index对应的表中继续寻找key,如果是函数则会调用此函数。此字段常用于解决默认值问题。
例子:

table = {"hey1", "hey2", "hey3"}
tmp = {[10] = "here's tmp"}
metaTable = {__index = tmp}
setmetatable(table, metaTable)
-- here's tmp
print(table[10])
function myIndex(table, index)
    print("Can't find", index)
    return table[1]
end
metaTable.__index = myIndex
-- Can't find 10
-- hey1
print(table[10])

__newindex字段对应的元方法会在表中插入一个之前没有的key时调用,一般用来监测表中插入新字段的操作。需要注意的是__newindex中不能对表进行直接赋值,否则还会调用__newindex,形成无限的递归。但是可以使用rawset函数,绕过__newindex进行赋值。
例子:

table = {}
setmetatable(table, {__newindex = function(table, key, value)
    print("Insert new pair")
    rawset(table, key, value .. "tttttt")
end
})
table["tmp"] = "tmp" -- Insert new pair
print(table["tmp"]) -- tmptttttt

__add字段与其他二元操作符

定义了表在相加时的行为,另一个相加数可以是基本类型、也可以是另一张表。
注意: 如果两个加数都是表,并且两表的元表中都有__add字段,默认使用“+”左边的表的规则。如果只有一张表有__add字段,那么就使用这张表定义的规则。

myTable1 = {1, 2, 3}
metaTable = {}
setmetatable(myTable1, metaTable)
-- 与数字相加
function myAdd1(table, num)
    for i,v in ipairs(table) do
        table[i] = v + num
        print(table[i])
    end
end
metaTable.__add = myAdd1
t = myTable1 + 1 -- 2 3 4
-- 两表相加
metaTable.__add = function()
    print("table1")
end
myTable2 = {3, 2, 1}
setmetatable(myTable2, {__add = function()
print("table2")
end})
tmp = myTable1 + myTable2 -- table1

其他的二元操作符如下:

字段描述
__sub减法
__mul乘法
__div除法
__mod取模
__unm相反数
__concat连接(…)
__eq等于
__lt小于
__le小于等于

__call字段与__tostring字段

call字段让表可以像函数一样被调用:

table = {"111", "222"}
function call(table, index)
    return table[index]
end
setmetatable(table, {__call = call})
print(table(2)) -- 222

tostring字段控制表转换为字符串的规则:

table = {"111", "222"}
function myToString(table)
    res = ""
    for _, v in pairs(table) do
        res = res .. tostring(v)
    end
    return res
end
setmetatable(table, {__tostring = myToString})
print(table) -- 111222
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值