【Lua学习笔记】Lua进阶——Table,迭代器

文章目录
- 官方唯一指定数据结构--table
- table的一万种用法
- 字典和数组
- 迭代器
- ipairs()
- pairs()
- 回到Table
在【Lua学习笔记】Lua入门中我们讲到了Lua的一些入门知识点,本文将补充Lua的一些进阶知识
官方唯一指定数据结构–table
在上篇文章的最后,我们指出通过查询_G的字符索引,发现table.insert实际上是一个名为table的table结构里的索引指向的函数
实际上不仅它,所有的函数,模块,全局变量,元表
我不知道作者是出于什么样的心理活动写出的Lua,但确实让我这个初学者大为震撼。
(以下内容摘抄自Lua语言:基础知识)
但是作为Lua中唯一的数据结构,table还是很万能的:
- 它可以用任何类型作索引,不止number和string,也可以使用其他类型(甚至function和table)
- Table功能强大,它即可以用作字典,也可以用作数组,配合元表机制还可以模拟面向对象。
- Lua的很多基础设施,比如模块,全局变量,元表,都是基于table实现的。
table的一万种用法
字典和数组
-- 当成字典使用
local t = {a = 1,b = true,c = "abc",
}
-- 当成数组使用
local t2 = {1, "aa", false}
这两种都是很自然的用法,既能作为字典,又能作为数组
但是它也可以同时表示字典和数组
local t3 = {1, 2, 3,a = "aaa",b = "bbb",
}
print(t3[1])
print(t3.a)
结果:
1
aaa
需要注意的是其中的数组和字典是以两种不同的方式存储的local t3 = {a = "aaa",1, 2,b = "bbb",3
}
print(t3.a)
print(t3[1])
print(t3[3])
结果:
aaa
1
3
从上述例子我们能看到,数字索引直接访问了数组元素略过了键值对,
使用键值对的key名才能访问字典中对应的值
使用下列模式使得它们在格式上更通用
local t3 = {[1] = 1, [2] = 2, [3] = 3,["a"] = "aaa",["b"] = "bbb",
}
但是上述只是个例子,在实践中,我们最好不混用字典和数组,这常常会引发混乱的问题。而从设计的角度看,它违反了单一职责原则,比如空Table就存在着二义性,如果它是空的,那么请问这种情况下它是数组还是字典?这往往会导致使用时的各种问题,例子请看下文迭代器。
迭代器
虽然迭代器并不属于Table的知识,但我认为在此处插入讲一下是比较合适的。主要就是pairs和ipairs的区别
ipairs()
返回三个值(迭代函数、表 t 以及 0 ), 如此,以下代码
for i,v in ipairs(t) do body end
将迭代键值对 (1,t[1]) ,(2,t[2]), ... ,直到第一个空值。
例子:
local tab = {23,35,[3] = 45,78,[8] = 101,nil,80
}for k,v in ipairs(tab) doprint(k..":"..v)
end
输出:
1:23
2:35
3:78
在上述例子中,ipairs遍历了数组,但在nil时停下,实际上这个table的结构应该是这样:
local tab: {[1]: integer = 23,[2]: integer = 35,[3]: integer = 45|78,[4]: nil,[5]: integer = 80,[8]: integer = 101,
}
来个更混乱的例子
local tab = {23,35,[3] = 45,78,["a"] = 5,[8] = 101,[3] = nil,1212,nil,80,["b"]=nil
}for k, v in ipairs(tab) doprint(k .. ":" .. v)
end
输出:
1:23
2:35
3:78
4:1212这是它的实际结构
local tab: {["a"]: integer = 5,["b"]: nil,[1]: integer = 23,[2]: integer = 35,[3]: integer|nil = 45|78,[4]: integer = 1212,[5]: nil,[6]: integer = 80,[8]: integer = 101,
}
可以看出ipair只会遍历数字key名的元素(也就是数组类型),并且当碰到nil时停下,而其他字典类型会被无视
而ipair会有三个返回值,分别是迭代函数,表,index。让我们看看这三个值在迭代器中是如何迭代的:
print("---index=0---")
funcA ,table, index =ipairs(tab)
for k, v in funcA, table, index doprint(k .. ":" .. v)
end
print("---index=1---")
for k, v in funcA, table, index+1 doprint(k .. ":" .. v)
end输出:
---index=0---
1:23
2:35
3:78
4:1212
---index=1---
2:35
3:78
4:1212
从上述例子中可以看到,index实际上代表了起始序列,当index=0,对应从table的数组标签[1]开始,当index=1,则从[2]开始
如果数组里有负数和0呢?
local tab = {[0] = 1,2,[-1] = 3,4,5,[5] = 6,
}
for k, v in ipairs(tab) doprint(k .. ":" .. v)
end
输出:
1:2
2:4
3:5
实际的table结构
local tab: {[0]: integer = 1,[1]: integer = 2,[-1]: integer = 3,[2]: integer = 4,[3]: integer = 5,[5]: integer = 6,
}
可以看到,0和负数都被ipairs自动略过了,有意思的是由于[4]没有定义,因此被认为是nil而停止了迭代。
总结:ipairs会略过数组的0和负数索引,以及其他字典索引,从数组的[1]索引开始迭代(对应index=0),顺序迭代直到某个索引不存在或其对应的值为空时结束
pairs()
让我们把上述几个例子用pairs遍历一下
local tab = {23,35,[3] = 45,78,[8] = 101,nil,80
}for k,v in pairs(tab) doprint(k..":"..v)
end
输出:
1:23
2:35
3:78
5:80
8:101
table的结构是这样:
local tab: {[1]: integer = 23,[2]: integer = 35,[3]: integer = 45|78,[4]: nil,[5]: integer = 80,[8]: integer = 101,
}
可以看到重复定义的元素值还是选择了后者,并且nil被无视了
local tab = {["b"]=8,[0] = 1,2,[-1] = 3,4,5,[5] = 6,["a"]=7,
}
for k, v in pairs(tab) doprint(k .. ":" .. v)
end
输出:
1:2
2:4
3:5
0:1
b:8
a:7
-1:3
5:6
实际的table结构
local tab: {[0]: integer = 1,[1]: integer = 2,[-1]: integer = 3,[2]: integer = 4,[3]: integer = 5,[5]: integer = 6,["a"]: integer = 7,["b"]: integer = 8,
}
有意思的是pairs是先按数字顺序输出了数组,然后碰到了不存在的索引[4],随后输出了0,b,a,-1。顺序十分诡异,最后才输出了[5]。我不知道为什么这样输出,但是这种输出方式也侧面证明了数组不要和字典一起定义!
总结:
ipairs会略过数组非正数索引,以及其他字典索引,从数组的[1]索引开始迭代(对应index=0),顺序迭代直到某个索引不存在或其对应的值为空时结束。
pairs可以输出table内除了nil以外的所有元素。但是数组和字典的混合以及带有非正值数字索引的元素输出方式会很诡异。
所以别用非正数索引(实际上非正索引应当称为自定义索引),也别把数组和字典定义在一个table里!
回到Table
table将key的值设为nil,它的真实含义是删除掉这个key,这和其他脚本很不一样,也可能引发一些问题,比如看下面例子:
local t = {1, 2, nil, 4}
print(#t) ---> 4
for k, v in ipairs(t) do print(v) end ---> 1 2
for k, v in pairs(t) do print(v) end ---> 1 2 4
for i = 1, #t do print(t[i]) end ---> 1 2 nil 4
可以看到使用迭代器是直接无视nil的,但使用for遍历会得到nil,我们本意是想删除这个元素,但是它依然存在于table中
那么nil不等于删除吗?请看下列的例子:
local t = {1, 2, nil, nil, 5}
print(#t) --> 5
t = {[1]=1, [2]=2, [3]=nil, [4]=nil, [5]=4}
print(#t) --> 2
直接定义nil时,nil是会计入table的长度的。但主动定义键值对时nil不会计入table的长度。因此当我们定义table时,应当以键值对的方式定义
过分吗?还有更过分的
a = { [1] = 1, [2] = 2, [5] = 5, [6] = 6 }
print(#a) -->2
b = { [1] = 1, [2] = 2, [4] = 4, [5] = 5, [6] = 6 }
print(#b) -->6
c = { [1] = 1, [2] = 2, [4] = 4, [5] = 5, [6] = 6, [9] = 9 }
print(#c) -->6
d = { [1] = 1, [2] = 2, [4] = 4, [5] = 5, [6] = 6, [8] = 8, [9] = 9 }
print(#d) -->6
发现了吗?键值对形式存储时,中间如果隔了一个nil,那么长度会接上;如果隔了两个nil长度就会断开
???
🧠
(O.o)>
相关文章:
【Lua学习笔记】Lua进阶——Table,迭代器
文章目录 官方唯一指定数据结构--tabletable的一万种用法字典和数组 迭代器ipairs()pairs() 回到Table 在【Lua学习笔记】Lua入门中我们讲到了Lua的一些入门知识点,本文将补充Lua的一些进阶知识 官方唯一指定数据结构–table 在上篇文章的最后,我们指出…...
重庆市北斗新型智慧城市政府项目
技术栈:使用vue2JavaScriptElementUIvuexaxiosmapboxcesium 项目描述:重庆市北斗新型智慧城市政府项目是基于千寻孪界开发的一款智慧城市项目,包含车辆实时位置定位,智能设备的报警,基础设施的部设等等功能 工作内容&a…...
FANUC机器人SRVO-217故障报警原因分析及参考解决办法
FANUC机器人SRVO-217故障报警原因分析及参考解决办法 如下图所示,示教器提示:SRVO-217紧急停止电路板未找到, 查阅手册可以看到以下的报警说明: 故障原因: 通电时未能识别紧急停止电路板或者增设的安全I/O装置。连接有多个安全I/O装置的系统中,在报警信息的最后,会显示发…...
统信UOS安装mysql数据库(mariadb)-统信UOS安装JDK-统信UOS安装nginx(附安装包)
统信UOS离线全套安装教程(手把手教程) 银河麒麟的各种离线全套安装教程: https://blog.csdn.net/ACCPluzhiqi/article/details/131988147 1.统信UOS桌面系统安装mysql(mariadb) 2.统信UOS桌面系统安装JDK 3.统信UOS桌…...
上门小程序开发|上门服务小程序|上门家政小程序开发
随着移动互联网的普及和发展,上门服务成为了许多人生活中的一部分。上门小程序是一种基于小程序平台的应用程序,它提供了上门服务的在线平台,为用户提供了便捷的上门服务体验。下面将介绍一些适合开发上门小程序的商家。 家政服务商家&am…...
1000道网络安全必备面试题合集,秋招金九银十必看!!!
以下为网络安全各个方向涉及的面试题,星数越多代表问题出现的几率越大,祝各位都能找到满意的工作。 注:本套面试题,已整理成pdf文档,但内容还在持续更新中,因为无论如何都不可能覆盖所有的面试问题&#x…...
从0-1实现简易Raft分布式共识算法
一、Raft前置简介 Raft目前是最著名的分布式共识性算法,被广泛的应用在各种分布式框架、组件中,如Redis、RocketMq、Kafka、Nacos(CP)等 根据Raft论文,可将Raft拆分为如下4个功能模块: 领导者选举日志同…...
Spring 创建和使用
Spring 是⼀个包含了众多⼯具⽅法的 IoC 容器。既然是容器那么它就具备两个最基本的功能: 将对象存储到容器(Spring)中; 从容器中将对象取出来。 在 Java 语⾔中对象也叫做 Bean 1.创建 Spring 项目 接下来使⽤ Maven ⽅式来创…...
Javadoc comment自动生成
光标放在第二行 按下Alt Shift j 下面是Java doc的生成 Next Next-> Finish...
vue3 +ts 报错 index.vue 不是模块
那是因为index.vue中创建了一个空的script标签,而且语法使用的是ts语法。vue-cli会用ts语法解析和校验 如果是无状态组件,删掉 如果是有状态组件,导出该组件的实例 去掉null的script后:...
win10 hadoop报错 unable to load native-hadoop library
win10 安装hadoop执行hdfs -namenode format 和运行hadoop的start-all报错 unable to load native-hadoop library 验证: hadoop checknative -a 这个命令返回都是false是错的 返回下图是正确的 winutils: true D:\soft\hadoop-3.0.0\bin\winutils.exe Native li…...
前端(九)——探索微信小程序、Vue、React和Uniapp生命周期
🙂博主:小猫娃来啦 🙂文章核心:探索微信小程序、Vue、React和Uniapp生命周期 文章目录 微信小程序、Vue、React和Uniapp的基本定义和应用领域微信小程序生命周期生命周期概述页面生命周期应用生命周期组件和API的生命周期钩子 Vu…...
MyBatis查询数据库(2)
目录 前言🍭 一、增删查改操作 1、查 Ⅰ、mapper接口: Ⅱ、UserMapper.xml 查询所有用户的具体实现 SQL: Ⅲ、进行单元测试 2、增、删、改操作 Ⅰ、增 添加用户 添加用户并且返回自增 id Ⅱ、改 根据id修改用户名 开启 MyBatis …...
Jenkins构建完成后发送消息至钉钉
钉钉群的最终效果: 1、jenkins安装DingTalk插件,安装完成后重启 2、配置钉钉插件 参考官网文档:快速开始 | 钉钉机器人插件 系统管理 拉到最下面,可以看到钉钉配置 按照如下配置钉钉机器人 配置完成可以点击测试按钮࿰…...
从浏览器输入url到页面加载(六)前端必须了解的路由器和光纤小知识
前言 上一章我们说到了数据包在网线中的故事,说到了双绞线,还说到了麻花。这一章继续沿着这条线路往下走,说一些和cdn以及路由器相关,运营商以及光纤相关的小知识,前端同学应该了解一下的 目录 前言 1. CDN和路由器…...
C语言假期作业 DAY 06
题目 一、选择题 1、以下叙述中正确的是( ) A: 只能在循环体内和 switch 语句体内使用 break 语句 B: 当 break 出现在循环体中的 switch 语句体内时,其作用是跳出该 switch 语句体,并中止循环体的执行 C: continue 语句的作用是&…...
[nlp] tokenizer加速:fast_tokenizer=True
fast_tokenizer 是一个布尔值参数,用于指定是否使用快速的 tokenizer。在某些情况下,使用快速的 tokenizer 可以加快模型训练和推理速度。如果 fast_tokenizer 参数为 True,则会使用快速的 tokenizer;否则,将使用默认的 tokenizer。 快速的 tokenizer 通常使用一些技巧来减…...
基于OpenCV solvePnP函数估计头部姿势
人脸识别 文章目录 人脸识别一、姿势估计概述1、概述2、姿态估计3、在数学上表示相机运动4、姿势估计需要什么5、姿势估计算法6、Levenberg-Marquardt 优化 二、solvePnP函数1、函数原型2、参数详解 三、OpenCV源码1、源码路径 四、效果图像示例参考链接 一、姿势估计概述 1、…...
STC12C5A系列单片机内部 EEPROM 的应用
参考范例程序。 eeprom.c #include "eeprom.h"/*---------------------------- Disable ISP/IAP/EEPROM function Make MCU in a safe state ----------------------------*/ void IapIdle() {IAP_CONTR 0; //Close IAP functionIAP_CMD 0; …...
搭建测试平台开发(一):Django基本配置与项目创建
一、安装Django最新版本 1 pip install django 二、创建Django项目 首先进入要存放项目的目录,再执行创建项目的命令 1 django-admin startproject testplatform 三、Django项目目录详解 1 testplatform 2 ├── testplatform # 项目的容器 3 │ ├──…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
