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

news2024/12/23 13:56:43

在这里插入图片描述

文章目录

  • 官方唯一指定数据结构--table
    • table的一万种用法
      • 字典和数组
  • 迭代器
    • ipairs()
    • pairs()
  • 回到Table

在【Lua学习笔记】Lua入门中我们讲到了Lua的一些入门知识点,本文将补充Lua的一些进阶知识


官方唯一指定数据结构–table

在上篇文章的最后,我们指出通过查询_G的字符索引,发现table.insert实际上是一个名为table的table结构里的索引指向的函数

实际上不仅它,所有的函数,模块,全局变量,元表

😅😅😅都 是 T A B L E😅😅😅

我不知道作者是出于什么样的心理活动写出的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) do
    print(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) do
    print(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 do
    print(k .. ":" .. v)
end
print("---index=1---")
for k, v in funcA, table, index+1 do
    print(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) do
    print(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) do
    print(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) do
    print(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)>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/791170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【windows】连接共享打印机提示:0x0000011B

【问题现象】 添加共享打印机的时候, 提示错误:0x0000011B。 【解决方法】 按winr键,在运行输入regedit 然后在注册表中找到路径: 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print 打开后,在右侧…

Android 之 Canvas API 详解 (Part 3) Matrix 和 drawBitmapMesh

本节引言: 在Canvas的API文档中,我们看到这样一个方法:drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) 这个Matrix可是有大文章的,前面我们在学Paint的API中的ColorFilter中曾讲过ColorMatrix 颜色矩阵,一个4…

Python 生成随机图片验证码

Python 生成随机图片验证码 在写一个Web项目的时候一般要写登录操作,而为了安全起见,现在的登录功能都会加上输入图片验证码这一功能,在利用Django开发Web项目的过程中,可以使用 Python 生成一个如下所示的图片验证码&#xff1a…

MVC与MVVM模式的区别

一、MVC Model(模型):用于处理应用程序数据逻辑,负责在数据库中存取数据。处理数据的crud View(视图):处理数据显示的部分。通常视图是依据模型数据创建的。 Controller(控制器&…

Leetcode-每日一题【剑指 Offer 51. 数组中的逆序对】

题目 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 示例 1: 解题思路 前置知识 分治法 设计思想: 将规模为n的问题分解为k个规模较小的子问题…

解析LED防蓝光灯珠技术原理

LED防蓝光灯珠能有效减少蓝光对眼睛的持续伤害,通过便携式光谱分析仪对比检测,使用LED防蓝光灯珠后,手机屏幕发出的蓝光强度得到了有效抑制,减少了有害蓝光对眼睛的伤害。LED防蓝光灯珠主要是通过将有害蓝光进行反射,或…

(css)AI智能问答页面布局

(css)AI智能问答页面布局 效果&#xff1a; html <!-- AI框 --><div class"chat-top"><div class"chat-main" ref"chatList"><div v-if"!chatList.length" class"no-message"><span>欢迎使…

<PrivateImplementationDetails>.ComputeStringHash 错误解决办法

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 CS0119 “PrivateImplementationDetails”是一个 类型&#xff0c;这在给定的上下文中无效 G:\\_Default.cs 26 活动 用 ILSPY 或者 .NET Reflector 、dnspy 等反编译出来之后 <Privat…

专访伊士曼中国区高管赵志伟:以创新应对新能源汽车后市场变化

受访人&#xff1a;伊士曼高性能膜事业部中国区商务总监赵志伟 新能源汽车发展至规模化阶段&#xff0c;以贴膜、保养维修为主的后市场产业迎来快速崛起&#xff0c;新能源消费者在汽车贴膜、改装和养护领域也表现出比燃油车更高频的需求度。 作为一家全球特种材料公司&#x…

【iOS】KVOKVC原理

1 KVO 键值监听 1.1 KVO简介 KVO的全称是Key-Value Observing&#xff0c;俗称"键值监听"&#xff0c;可以用于监听摸个对象属性值得改变。 KVO一般通过以下三个步骤使用&#xff1a; // 1. 添加监听 [self.student1 addObserver:self forKeyPath:"age"…

Windows实现端口转发(附配置过程图文详解)

文章目录 1. 前言2. 命令提示符3. 防火墙4. netsh 命令4.1 查看已有的转发规则4.2 新增转发规则4.3 删除转发规则 5. 图解汇总6. 欢迎纠正~ 1. 前言 利用Windows端口转发&#xff0c;实现本地设备 ⬅➡ 公网主机 ⬅➡ 远端服务器 2. 命令提示符 以管理员身份打开“命令提示…

【雕爷学编程】Arduino动手做(88)---水流量传感器模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

2023年深圳杯数学建模C题无人机协同避障航迹规划

2023年深圳杯数学建模 C题 无人机协同避障航迹规划 原题再现&#xff1a; 平面上A、B两个无人机站分别位于半径为500 m的障碍圆两边直径的延长线上&#xff0c;A站距离圆心1 km&#xff0c;B站距离圆心3.5 km。两架无人机分别从A、B两站同时出发&#xff0c;以恒定速率10 m/s…

Codeforces Round 888 (Div. 3)

原题链接&#xff1a;Dashboard - Codeforces Round 888 (Div. 3) - Codeforces 目录 A. Escalator Conversations B. Parity Sort C. Tiles Comeback D. Prefix Permutation Sums E. Nastya and Potions F. Lisa and the Martians A. Escalator Conversations 题意&…

【Python从入门到人工智能】14个必会的Python内置函数(7)——数据格式化处理综合应用场景 (实现程序主界面)

总觉得忍一忍就会好起来。真笨&#xff0c;人家不就是觉得你会忍一忍&#xff0c;所以才这样对你吗&#xff1f;当我们凶狠地对待这个世界的时候&#xff0c;才会发现这个世界&#xff0c;突然变得温文尔雅了。——余华《在细雨中呼喊》 &#x1f3af;作者主页&#xff1a; 追光…

第二章:Learning Deep Features for Discriminative Localization ——学习用于判别定位的深度特征

0.摘要 在这项工作中&#xff0c;我们重新审视了在[13]中提出的全局平均池化层&#xff0c;并阐明了它如何明确地使卷积神经网络&#xff08;CNN&#xff09;具有出色的定位能力&#xff0c;尽管它是在图像级别标签上进行训练的。虽然这个技术之前被提出作为一种训练规范化的手…

Docker构建Nginx镜像并部署前台应用

文章目录 1. 简介2. 准备工作3. 编写Dockerfile4. 编写nginx.conf5. 构建镜像6. 查看镜像是否构建成功7. 运行容器8. 访问Web应用9. 总结 1. 简介 Docker是一个开源的容器化平台&#xff0c;它可以帮助我们快速构建、发布和运行应用程序&#xff0c;实现应用程序的环境隔离和依…

全国大学生数据统计与分析竞赛2021年【本科组】-B题:用户消费行为价值分析

目录 摘 要 1 任务背景与重述 1.1 任务背景 1.2 任务重述 2 任务分析 3 数据假设 4 任务求解 4.1 任务一&#xff1a;数据预处理 4.1.1 数据清洗 4.1.2 数据集成 4.1.3 数据变换 4.2 任务二&#xff1a;对用户城市分布情况与分布情况可视化分析 4.2.1 城市分布情况可视化分析 4…

PWM定时器精准定时实现led闪烁(S3C2440裸机开发)

文章目录 前言一、PWM定时器原理二、使用步骤总结 前言 上期和大家分享了使用PWM定时器输出周期方波驱动蜂鸣器&#xff0c;那么本期分享的内容是使用PWM定时器实现定时器的功能&#xff0c;有了上期的基础&#xff0c;这期分享的内容大家理解起来应该非常easy&#xff0c;接下…

Psyco模块能优化Python的运行速度吗

目录 什么是Psyco模块 Psyco模块有什么作用 什么时候用Psyco模块 Psyco模块能优化Python的运行速度吗 总结 什么是Psyco模块 Psyco是一个用于优化Python代码的第三方模块。它的目标是通过即时编译&#xff08;Just-In-Time Compilation&#xff09;技术来提高Python程序的…