Lua中table的ipairs和pairs以及function的:和.区别

本文详细介绍了Lua中使用ipairs和pairs遍历table的区别,通过示例展示了如何遍历数组和非数组部分。同时,文章还探讨了Lua中function的:和.的不同之处,帮助读者理解如何正确调用方法。

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

转载请注明出处:csdn火木达人

Lua中table遍历ipairs和pairs的区别
pairs()函数基本和ipairs()函数用法相同, 区别在于pairs()可以遍历整个table, 即包括数组及非数组部分.ipairs()函数用于遍历table中的数组部分.

local tableA = {1,2,suncle = "xxx",20};
tableA[10] = 10;
local tableB = {1,2,3};

for k,v in ipairs(tableA) do
    print("ipairs tableA : k = " .. k .. " --- v = " .. tostring(v));
end

for k,v in pairs(tableA) do
    print("pairs tableA : k = " .. k .. " --- v = " .. tostring(v));
end

for k,v in ipairs(tableB) do
    print("ipairs tableB : k = " .. k .. " --- v = " .. tostring(v));
end

for k,v in pairs(tableB) do
    print("pairs tableB : k = " .. k .. " --- v = " .. tostring(v));
end

另一种遍历连续的数组部分的方法:

print("#tableA = " .. #tableA);
for i=1,#tableA do
    print(tostring(tableA[i]));
end

Lua中function的:和.区别

local tableA = {};
function tableA:funcA()
    print("funcA self = " .. tostring(self));
end

function tableA.funcB(self)
    print("funcB self = " .. tostring(self));
end

function tableA.funcC()
    print("funcC self = " .. tostring(self));
end

tableA:funcA();-- : 默认会把tableA传进funcA中,默认接受的是self
tableA.funcA(tableA); -- . 没有默认的传递值,如果方法是定义成function tableA:funcA()形式的,需要现实的把tableA传进去
tableA.funcA(); -- 这种方式 self为空

tableA:funcB();--这种方式会默认传递自己,所以如果要用.去声明方法,需要现实的接受function tableA.funcB(self)
tableA.funcB();--没有默认传值,所以self为空
tableA.funcB(tableA);--显示的传值

tableA:funcC();
tableA.funcC();


<think>我们正在讨论Lua中的table数据结构。根据引用,tableLua中唯一的数据结构机制,用于实现数组、字典、对象等。它非常灵活,可以同时包含数组部分哈希部分。首先,table的创建通过构造表达式完成,例如:```luat={}--创建一个空表```我们可以像数组一样使用整数索引,也可以像字典一样使用任意类型的键(除了nil)。例如:```luat={1,2,3,a=4,b=5}--同时包含数组部分(1,2,3)哈希部分(a=4,b=5)```注意,数组部分从1开始索引(Lua的约定)。我们可以通过下标访问:```luaprint(t[1])--输出1print(t["a"])--输出4,也可以写成t.a```table是动态的,可以随时添加或删除元素。例如:```luat.c=6--添加新键值对t[4]=7--添加到数组部分```遍历table可以使用`pairs``ipairs`。`ipairs`遍历数组部分(连续整数键),`pairs`遍历所有键值对。例如:```luafori,vinipairs(t)doprint(i,v)--输出数组部分:1,2,3,4(注意这4是刚添加的,但注意ipairs只遍历连续的部分,如果中间有空洞则停止)endfork,vinpairs(t)doprint(k,v)--输出所有键值对,包括a,b,c以及数组部分(但数组部分在哈希部分也可能出现,实际内部由两个部分组成)end```注意:table内部由数组部分哈希部分构成。数组部分存储连续整数键(从1开始)的元素,哈希部分存储其他键。Lua会自动调整这两部分的大小以优化性能。另外,引用[4]提到Lua5.2.1对字符串键的处理进行了优化,防止哈希碰撞攻击。对于短字符串,使用专门的函数`luaH_getshortstr`快速查找。使用table时需要注意:1.避免在数组部分中间出现空洞(nil),这会导致`ipairs`提前终止,并且可能影响性能(数组部分会被截断,剩余元素移到哈希部分)。2.表的长度操作符`#`只针对数组部分,且要求数组部分没有空洞(即连续到第一个nil)。例如:```luat={1,2,3}print(#t)--3t[5]=5print(#t)--3,因为t[4]是nil,所以数组部分长度为3```高级用法:table可以用于实现各种数据结构。例如:-栈:使用数组部分,通过`table.insert``table.remove`(注意这些操作在数组中间进行会移动元素,效率较低)。-队列:可以使用两个索引(头尾)来避免移动元素,或者使用循环数组。-集合:将元素作为键,值设为true。-图:用邻接表,即每个节点对应一个table,存储相邻节点。最后,tableLua中是通过引用来传递的。赋值或传递参数时不会复制整个表,而是共享同一个引用。如果需要复制,必须自己实现复制函数(深拷贝或浅拷贝)。例如:```luat1={1,2,3}t2=t1--t2t1引用同一个表t2[1]=10print(t1[1])--10--浅拷贝函数functionshallow_copy(t)localres={}fork,vinpairs(t)dores[k]=vendreturnresendt3=shallow_copy(t1)--创建一个新表,但嵌套的表仍然是引用```关于元表(metatable),它可以改变table的行为,比如定义运算符、访问不存在的键等。这是Lua实现面向对象重载的关键。例如,我们可以定义两个表的加法:```luat1={1,2,3}t2={4,5,6}mt={}mt.__add=function(a,b)localres={}fori=1,#adores[i]=a[i]+b[i]endreturnresendsetmetatable(t1,mt)setmetatable(t2,mt)t3=t1+t2--调用mt.__add(t1,t2)print(t3[1],t3[2],t3[3])--5,7,9```总之,Luatable是核心数据结构,理解其内部机制用法对于高效使用Lua至关重要。§§相关问题§§1.Luatable的数组部分哈希部分是如何工作的?2.如何避免在Luatable中出现空洞(nil)对性能的影响?3.Lua的元表(metatable)有哪些常见用途?4.如何实现Luatable的深拷贝?5.Lua中如何用table实现面向对象编程?</think>### Lua中的table数据结构理解与使用 Luatable是其**核心数据结构**,也是唯一的内置数据结构,用于实现数组、字典、对象等多种数据组织形式[^1][^2]。它本质上是一个**关联数组**(associative array),既能通过整数索引(类似数组),也能通过任意类型键值(包括字符串、函数等)访问数据[^3]。 #### 基本特性 1. **灵活构造** 可同时包含数组部分哈希部分: ```lua -- 混合类型示例 myTable = { 1, 2, 3, -- 数组部分(索引1,2,3) name = "Lua", -- 字符串键 [5] = "index5", -- 整数键 [true] = "boolean key", -- 布尔键 func = function() print("Hi") end -- 函数值 } ``` 2. **动态扩展** - 无需预定义大小 - 可随时增删元素: ```lua myTable.newKey = "dynamic" -- 添加新键 myTable[1] = nil -- 删除元素(数组部分会留下空洞) ``` #### 关键操作 1. **访问元素** ```lua print(myTable.name) -- 输出 "Lua" print(myTable[1]) -- 输出 1 print(myTable[true]) -- 输出 "boolean key" ``` 2. **遍历方式** - 数组部分遍历(连续整数索引): ```lua for i, v in ipairs(myTable) do print(i, v) -- 输出 1,2,3(跳过非整数索引) end ``` - 全表遍历: ```lua for k, v in pairs(myTable) do print(k, v) -- 输出所有键值对 end ``` 3. **实现数据结构** - **数组**:连续整数索引 ```lua arr = {"a", "b", "c"} ``` - **字典**:字符串键值对 ```lua dict = {x=10, y=20} ``` - **集合**:键作为元素存在性标志 ```lua set = {["apple"]=true, ["orange"]=true} ``` #### 性能优化机制 Lua内部通过**混合存储**提升效率: - **数组部分**:连续整数键元素存储在数组中($O(1)$访问) - **哈希部分**:其他键值存储在哈希表(解决冲突采用开放寻址法)[^4] - 当数组部分出现空洞(`nil`)时,部分元素会迁移到哈希部分 #### 高级应用 1. **元表(Metatable)** 通过`__index`、`__newindex`等元方法实现面向对象: ```lua Person = {} function Person:new(name) local obj = {name = name} setmetatable(obj, {__index = Person}) return obj end ``` 2. **模块模式** 用table封装模块: ```lua myModule = {} function myModule.func1() ... end return myModule ``` #### 注意事项 1. 数组长度操作符`#`仅对**连续整数索引部分**有效 2. 避免在数组中间插入`nil`,这会导致长度计算不准确 3. 大表操作注意性能:插入/删除可能触发**重新哈希**(rehash)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值