Lua 数据类型 —— 表

2023-11-13

一、简介

表永远是匿名的,表本身和保存表的变量之间没有固定关系。

对于一个表而言,当程序不再有变量指向他时,垃圾收集器会最终删除这个表并重用其占用的内存。

Lua 不会进行隐藏拷贝或创建新表,操作的都是指向表的指针。

二、元素

1、键

表的键可以具有不同的类型,并且可以按需增长容纳新的元素

如果 table 是一个序列,则下标是从 1 开始,切记不是从 0 开始。

不能用 nil 作为键,否则会抛 table index is nil 错误

2、值

表的值可以通过赋值 nil 进行删除原有的项

3、获取元素

第一种: table[key]

类似 java 、 kotlin 的 map 取值 ,如果 key 对应的值并不存在,则返回 nil

第二种: table.key

这种取值等价于 table[“key”] ,记得这里是字符串,而不是 table[key]

table[key] 和 table.key 区别

两种方式从使用的角度来说是没有任何的区别

从语义上说,table[key] 表示表可以使用任意字符串作为键,table.key 表示表是被当作结构体使用,表实际上由固定的,预先定义的键组成集合

k = "jiang"
a = {}
a[k] = 28
a[29] = "xiao"

-------------
-- 这里的 a 表有以下内容
-- "jiang" --> 28
-- 29      --> "xiao"
-------------

print(a[k])         --> 28
print(a.k)          --> nil         a.k 相当于 a["k"],所以就没有值
print(a.jiang)      --> 28          a.jiang 相当于 a["jiang"]

4、数值作为键

任何能够被转换为整型的浮点数都会被转换成整型数(和之前数值一章的分享不谋而合)

c = {}
c[2.0] = 10
print(c[2])     --> 10 

三、表构造器

无论用哪种构造的表,都可以用 nil 赋予到对应的 key 删除对应的值。

空构造器

table1 = {}

列表式

这种方式运行速度更快一点(相比于记录式),因为能够提前判断表大小。键会是从 1 开始往上递增的值。

-- 列表式,键会是从 1 开始往上递增的值
table2 = { "Jiang", "peng", "yong", }   -- 最有的逗号是合法的,但不会被当作元素

--> 表结构
--> 1 -- "Jiang"
--> 2 -- "peng"
--> 3 -- "yong"

记录式

key 值会被当作字符串使用,例如下面的 a key,最终形态是 “a” ,所以可以使用 table3.a 。

table3 = { a = "1", b = 20, c = "3" }
print("table3 length: " .. #table3)         --> table3 length: 0        -- 因为 lua 表并不会进行维护长度,只会记录序列的下标作为表的长度
print(table3.a, table3["b"], table3.c)      --> 1	20	3

--> 表结构
--> "a" -- "1"
--> "b" -- 20
--> "c" -- "3"

混合两种

混合使用并不会有冲突,列表式的记录会从下标为 1 开始累加,记录式则还是继续使用自己的 key 。

table4 = { name = "江澎涌", { 170, "cm" }, age = 28, { "专业", "软件工程" } }
print("table4 length: " .. #table4)                             --> table4 length: 2
print(table4.name, table4.age, table4[1][1], table4[2][2])      --> 江澎涌	28	170	软件工程

通用式

这种方式最为灵活,虽然使用起来麻烦些。

即通过方括号括起来的表达式显示地指定每一个索引

可以使用一些 “特殊字符” 或 “负数” 一类进行作为 key ,也可以在方括号中使用计算表达式,使用其结果作为 key 值。

table5 = { [-1] = "j", "i", ["a"] = "a", "n", c = "g" }
print("table5 length: " .. #table5)         --> table5 length: 2
print(table5[1], table5[-1])                --> i	j

四、表长度

table 没有维护一个类似 java 、 kotlin 中 map 的 size 的尺寸。所以我们需要自己进行维护变量进行存储,可以存放在下面几个地方:

  1. 存储在一个常量中
  2. 存放在其他变量或数据结构中
  3. 存放在 table 中某个非数值类型的字段中,一般使用 “n” 作为 key

1、序列长度

序列是指不存在空洞(nil,所有的元素都不为nil)的有序列表。

序列可以使用 #table 进行获取长度。不包括数值类型 key 的 table 就是长度为零的序列。

处理有空洞的列表则需要自行维护长度,不然 #table 不可靠

从下面代码段的最后可以看出,存在空洞的 table 长度已经不可靠了。因为存在 nil 的行为程序不好定义程序猿想表达的目的是删除(则长度应该不算该值),还是有意让该 key 值为一个 nil 值(则长度应该算该值)。总而言之,如果能保证是无空洞序列的话,则可以使用 “#” 计算长度,否则自行维护。

sequence = {}
for i = 1, 10 do
    sequence[i] = i * i;
end
print("sequence size(没有空洞): " .. #sequence)           --> sequence size(没有空洞): 10

sequence[5] = nil   
print("sequence size(存在空洞,[5] = nil ): " .. #sequence)   --> sequence size(存在空洞,[5] = nil ): 10 (其实没有 10 个值)

sequence[10] = nil
print("sequence size(存在空洞,[10] = nil ): " .. #sequence)  --> sequence size(存在空洞,[10] = nil ): 9 (删除了最后一个,其实这里第 5 个和第 10 个都被删除了)

sequence[11] = 11 * 11
print("sequence size(存在空洞,[11] = 11*11 ): " .. #sequence)    --> sequence size(存在空洞,[11] = 11*11 ): 11
sequence[10] = 100
print("sequence size(存在空洞,[100] = 100 ): " .. #sequence)     --> sequence size(存在空洞,[100] = 100 ): 11

2、遍历计算长度

利用 pairs 会将所有的元素都遍历一次的特性,进行计算 table 中有多少元素。pairs 在下一小节进行分享

function table_leng(t)
  local leng = 0
  for k, v in pairs(t) do
    leng = leng+1
  end
  return leng;
end

五、表遍历方式

三种遍历方式

1、paris

因底层实现问题,pairs 不会确保顺序,可能每次遍历结果都不同,但每个元素一定会出现一次

table5 = { 10, print, x = 12, k = "hi" }
for k, v in pairs(table5) do
    print(k, "-->", v)
end

--> 1	-->	10
--> 2	-->	function: 0x109cdeac0
--> x	-->	12
--> k	-->	hi 

2、ipairs

列表可以用 ipairsipairs 会确保顺序进行,不是数字或是不连续(有空洞)则会被跳过

print("ipairs 遍历")
table6 = { 10, print, 12, "hi"}
table6[10] = 111
table6["a"] = 100
for i, v in ipairs(table6) do
    print(i, "-->", v)
end

--> ipairs 遍历
--> 1	-->	10
--> 2	-->	function: 0x106f13ac0
--> 3	-->	12
--> 4	-->	hi

3、序列下标遍历

table6 = { 10, print, 12, "hi" }
for i = 1, #table6 do
    print(i, "-->", table6[i])
end

--> 序列数值遍历
--> 1	-->	10
--> 2	-->	function: 0x106f13ac0
--> 3	-->	12
--> 4	-->	hi

六、安全操作符

Lua 中没有安全操作符,不像 kotlin 中有 ?. 这样的操作,但可以通过 nullable or default 的格式进行操作,例如下面操作

E = {}
company = { }
zip = (((company or E).director or E).address or E).zipcode

类似 kotlin 中

var zip = company?.director?.address?.zipcode

举个例子

这里就是利用了 or 的特性

print("模拟安全操作: ")
----- 安全操作 -------
E = {}
company = nil
zipcode = (((company or E).director or E).address or E).zipcode or "default"
print(zipcode)          --> default
company = { director = { address = { zipcode = "10080" } } }
zipcode = (((company or E).director or E).address or E).zipcode or "default"
print(zipcode)          --> 10080

七、表标准库操作

只针对列表、序列操作,所有的操作下标开始是 1

1、insert(table, index, item)

在 table 的 index 下标插入 item ,如果 index 越界了,则会抛出 bad argument #2 to 'insert' (position out of bounds)

table7 = { 10, 20, 30 }
showTable(table7)       --> [1]=10, [2]=20, [3]=30, 
table.insert(table7, 2, 909)
showTable(table7)       --> [1]=10, [2]=909, [3]=20, [4]=30,

如果不设置插入下标,则默认插在末尾

table.insert(table7, 50)
showTable(table7)       --> [1]=10, [2]=909, [3]=20, [4]=30, [5]=50, 

2、remove(table, index)

移除 table 的 index 下标的元素,会有一个返回值,即被移除的元素,则会抛出 bad argument #1 to 'remove' (position out of bounds)

table.remove(table7, 3)
showTable(table7)       --> [1]=10, [2]=909, [3]=30, [4]=50, 

如果不设置下标参数,则移除末尾

table.remove(table7)
showTable(table7)       --> [1]=10, [2]=909, [3]=30, 

3、move(table, startIndex, endIndex, newIndex)

move 只是负责移动元素,并不会附带删除,如果需要删除,则需要自行对元素进行设置为 nil

将 table 中从 startIndex 到 endIndex 的元素( [ startIndex, endIndex ] ),复制到 newIndex 下标开始。

move 模拟在开头插入元素
table.move(table7, 1, #table7, 2)
table7[1] = 0
showTable(table7)        --> [1]=0, [2]=10, [3]=909, [4]=30, 
move 模拟删除第一个元素,记得要将末尾进行 nil 删除,否则最后元素还存在
table.move(table7, 2, #table7, 1)
table7[#table7] = nil
showTable(table7)          --> [1]=10, [2]=909, [3]=30, 
使用 move 可以进行 table 间的拷贝,即使用 table(table, startIndex, endIndex, newIndex, newtable)

需要多传入一个 table , 第四个参数指定的是 table 开始赋值的下标

-- move 将表 a 拷贝到表 b , 可以通过 (#b + 1) 将元素接到表 b 末尾
table8 = { 20, 20, 30, 40, 50 }
table.move(table7, 1, #table7, #table8 + 1, table8)
showTable(table7)   --> [1]=10, [2]=909, [3]=30, 
showTable(table8)   --> [1]=20, [2]=20, [3]=30, [4]=40, [5]=50, [6]=10, [7]=909, [8]=30, 

4、sort(table, sortfunction)

对 table 排序

table9 = {
    { name = "xiao peng you", age = 20 },
    { name = "zinc", age = 27 },
    { name = "jiang peng yong", age = 28 },
}
for i, v in ipairs(table9) do
    print(i, "-->", v.name, "--", v.age)
end

--> 1	-->	xiao peng you	--	20
--> 2	-->	zinc	--	27
--> 3	-->	jiang peng yong	--	28

table.sort(table9, function(a, b)
    return #a.name > #b.name
end)
for i, v in ipairs(table9) do
    print(i, "-->", v.name, "--", v.age)
end

--> 1	-->	jiang peng yong	--	28
--> 2	-->	xiao peng you	--	20
--> 3	-->	zinc	--	27

值得注意

使用 insertremove 函数时,如果针对中间元素进行操作,则会导致后面的元素移动,会有额外的开销。

八、写在最后

Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)

公众号搜索 “江澎涌” 可以更快的获取到后续的更新文章

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Lua 数据类型 —— 表 的相关文章

  • 用dagger 2查看依赖注入

    我有一个自定义视图扩展TextView 我应该在哪里调用我的组件来注入视图 component inject customTextView 因此 我发现我需要在自定义视图的构造函数中添加注入 在所有视图中 或者使一个调用另一个 Exampl
  • NHibernate IQueryable 集合作为 root 的属性

    我有一个根对象 它有一个集合属性 例如 I have a Shelf object that has Books Now public class Shelf public ICollection
  • 增量决策树 C++ 实现

    有谁知道决策树分类器的增量实现吗 这样 当您将新实例添加到训练集中时 它可以根据现有决策树分类器以低计算量并尽可能快地生成最佳决策树分类器 换句话说 我有一个最优决策树分类器集A 其中命名为T 1 现在我想添加实例X to set A并找到
  • 还有其他地方可以获得 google-services.json 吗?

    我尝试单击GET A CONFIGURATION FILE链接自the docs https developers google com identity sign in android start integrating get conf
  • android listactivity onCheckedChangeListener

    我正在开发一款应用程序 并且我有一个ListActivity 其选择模式设置为choice mode multiple 现在我想重写方法 当一项被调用时调用该方法选中 未选中 我发现onCheckChanged 方法仅针对RadioGrou
  • std::tr1::function 和 std::tr1::bind

    我在使用时遇到问题veryC 类中的复杂 C 函数 重写 C 函数是not一个选项 C函数 typedef void integrand unsigned ndim const double x void fdata unsigned fd
  • 在 WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER 处出现错误

    我正在通过以下方式创建我的第一个动态壁纸this http www vogella com articles AndroidLiveWallpaper article html教程 但我收到错误can not be resolved or
  • 我的 WPF 应用程序未触发 MainWindow_Loaded

    我目前正在关注Pluralsight C Fundamentals Part 1并在Classes and Objects视频部分指导我在 Visual Studio 中创建一个新的 WPF 应用程序并填写代码 这导致以下结果 namesp
  • 如何在 Jetpack Compose 中集成自动填充

    我想在我的应用程序中提供一些自动填充功能 电子邮件和密码 该功能完全使用 Jetpack compose 编写 我碰到这篇博文 https bryanherbst com 2021 04 13 compose autofill and 这个
  • 如何删除实体框架6中的多对多关系

    如果将项目连接为多对多关系 则从数据库中删除项目时会出现问题 我的数据库看起来像 Project lt JobInProject gt Job ProjectID JobInProjectID JobID ProjectID JobID 主
  • 如何在Azure功能中添加razor视图文件?

    我正在创建一个应用程序 它是 azure 函数项目 我想在该项目中使用 Razor 视图 我应该在 azure 函数中使用任何模板引擎吗 得益于一些方面的进步剃刀之光项目 https github com toddams RazorLigh
  • 修改正在运行的可执行文件的资源内容

    All 我将应用程序设置存储在资源中 当我的程序首次加载时 我使用 WinAPI 读取指定的资源 然后我解析检索到的字节数据 这对我来说完美无缺 现在假设用户更改了我的应用程序中的设置 他 她检查复选框控件 我想将更新的设置保存到我的资源中
  • Identity Server 4:添加访问令牌的声明

    我正在使用 Identity Server 4 和隐式流 并且想要向访问令牌添加一些声明 新的声明或属性是 tenantId 和 langId 我已将 langId 添加为我的范围之一 如下所示 然后通过身份服务器请求 但我也获得了tena
  • Nuget - 对象引用未设置为对象的实例

    我在 vs 2015 中遇到了 nuget 包管理器的问题 像Unity这样的一些包已经安装没有问题了 某些软件包 例如 EF 在安装时出现问题 像 Automapper 这样的一些软件包也有同样的问题 但是当我安装这个软件包的另一个版本时
  • 生成范围 [min,max] 内的随机数 [重复]

    这个问题在这里已经有答案了 我正在使用 C 生成范围 min max 内的整数随机数 我在用 int random int int min int max return min rand max min 但我认为上面的代码适用于范围 min
  • C# 3.0 中自动属性和公共字段的区别

    我无法理解为什么 C 3 0 中存在自动实现的属性语言功能 当你说的时候有什么区别 public string FirstName than public string FirstName get set 因为它们在生成的 IL 代码 和机
  • 在Framework 4.6项目中使用.net core DLL

    我已经在 net core 2 0 中构建了一个 DLL 现在我想在使用 net 4 6 1 框架的 WinForms 项目中使用它 我可以引用该 dll 但收到 System IO FileLoadException 表示找不到 Syst
  • 是否可以编写一个在另一个 Windows 应用程序中选择文本时收到通知的 Windows 应用程序?

    我很好奇是否可以编写一个程序来监视我的文本选择 一种可能的用途是编写一个与编辑器 IDE 无关的代码格式化程序 应用程序 服务 P 启动并以某种方式挂接到窗口中 以便在任何窗口中选择文本时收到通知 启动其他一些应用程序 A 用户选择 A 中
  • 替换全局热键

    我有一个位于托盘中的应用程序 我想定义多个热键来触发我的程序中的事件 我从 AaronLS 在这个问题中的出色回答中找到了灵感 使用C 设置全局热键 https stackoverflow com a 27309185 3064934 如果
  • 如何使用 Ioc Unity 注入依赖属性

    我有以下课程 public interface IServiceA string MethodA1 public interface IServiceB string MethodB1 public class ServiceA IServ

随机推荐

  • 最近大热的 chatGPT 会取代你的工作吗?

    ChatGPT 由于其高效的自然语言处理能力 它最容易取代的领域可能是 文本分类 ChatGPT 可以用作文本分类系统 对文本进行分类 聊天机器人 ChatGPT 可以制作聊天机器人 提供人性化的交互体验 文本生成 ChatGPT 可以生成
  • 小米生态企业强力推荐的开源免费SRM采购管理平台功能介绍

    本文节选自Odoo亚太金牌服务机构 开源智造 所编写的 ERP真的免费不花钱 Odoo应用指南 如需获取完整的知识内容 请至开源智造官网免费获取 感谢网友一键三连 点赞 转发 收藏 您的支持是我们最大的前进动力 概述 采购工作起源于采购请求
  • swagger设置字段required必填

    swagger注解中需要设置请求参数的字段是必须填写的还是非必须的 我们需要添加下面的配置 只需要在对象的字段中增加下面的代码 ApiModelProperty value 自建应用的corpid required true 显示效果如下
  • Vulnhub实战-prime1

    前言 VulnHub 是一个面向信息安全爱好者和专业人士的虚拟机 VM 漏洞测试平台 它提供了一系列特制的漏洞测试虚拟机镜像 供用户通过攻击和漏洞利用的练习来提升自己的安全技能 本次 我们本次测试的是prime1 一 主机发现和端口扫描 查
  • Python 、Pychorm 、 Opencv安装及环境变量的配置--opencv不能调用cv2

    Python Pychorm Opencv安装及环境变量的配置 Python安装及环境变量的配置 1 Python下载安装 官网下载Python安装包 Python官网 https www python org Python在安装时 提示可
  • flex 一行两个_flex 方式的布局你用对了吗?

    对于 CSS 中的 flex 弹性布局 曾经我在公众号里写过 一点点对 flex 布局有关的看法 和 又一次想说 flex 布局挖坑给你 信吗 印象中最深的一个点 是我在文中提到的对于 flex 的这个属性中的三个属性值怎么用的话题 如果你
  • 初等变换法求解线性方程组

    初等变换 通过初等行 列同理 变换把增广矩阵变为简化阶梯型矩阵的线性方程组求解算法 具体步骤 枚举每一列 找到枚举的当前列绝对值最大数的所在行 将该行换到最上面一行 第r行 将该行第一个数 该行第c列元素 消成1 将该行第一个元素 该行第c
  • PCB中如何区分电源线和信号线

    在电路设计中 我们需要区分电源线和信号线 电源线主要负责传输电能和提供稳定的电压给整个电路系统 而信号线则传输各种数据 信息和控制电路 当我们开始画 PCBA 时 通常会采用颜色编码来区分电源线和信号线 以下是一些常见的方法 电源线通常使用
  • 常用邮件客户端软件设置

    文章来源 http service mail qq com cgi bin help subtype 1 id 28 no 371 2 您可以使用支持POP3的客户端软件 例如Foxmail或Outlook 收发您的邮件 请配置您的电子邮件
  • CentOS7搭建httpd服务

    文章目录 httpd 1 httpd安装 使用yum安装 httpd命令 curl命令 编译安装httpd 2 4 2 httpd常用配置 访问控制法则 3 虚拟主机 相同ip不同端口的配置 不同IP相同端口配置 相同IP相同端口不同域名配
  • QT Creator工具介绍及使用

    一 QT的基本概念 QT主要用于图形化界面的开发 QT是基于C 编写的一套界面相关的类库 如进程线程库 网络编程的库 数据库操作的库 文件操作的库等 如何使用这个类库 类库实例化对象 构造函数 gt 学习类库中方法 函数 的使用 gt 后台
  • 今天觉得自己太菜了!!!!

    今天觉得自己太菜了 转载于 https www cnblogs com zhangzheny archive 2007 01 24 629460 html
  • 如何检测tensorflow是否使用CPU还是GPU计算

    输入如下命令 python import tensorflow as tf sess tf Session config tf ConfigProto log device placement True 若包含CPU信息 则使用了CPU 若
  • GBDT 学习

    花絮 最近加班疯掉了 比九九六还要多 不行啊 这个便宜一定要从老板身上占回来 另外不知道朋友们是怎么学习一个新算法的 不过我一般是直接百度很多关于这个算法的博客来看 你会发现有些地方可能相互补充 有的地方可能互相矛盾 这种情况可不少见 总之
  • python是一门面向对象的编程语言_python面向对象(面向对象、面向过程、类、参数self)...

    年轻人 你渴望力量吗 你渴望拥有对象吗 让我们面向对象 重建 家园 吧 一 面向对象的简介 众所周知 python是一门面向对象的编程语言 但是 你知道什么是面向对象吗 在说面向对象之前 我们先来说一说什么是对象 之前的博客有简单涉入 一
  • ANT 安装使用及build.xml文档模板

    一 安装 下载地址 http archive apache org dist ant 0 前提 已经正确设定了JAVA HOME的系统变量 1 直接解压 到D apache ant 1 7 2 系统环境变量中设置 path 加上 D apa
  • chatgpt赋能powershell

    最近chatgpt非常火爆 获得超高曝光度的同时 也让大家对ai和ai工具有了新的认识 关于chatgpt 可以参考这篇文章 今天主要推荐一个可以与powershell集成的ai工具 其后端也是openai的服务 可以有效提高工作效率 Po
  • vue3 element plus NavMenu 导航无法选中(同级页面跳转,导航无法高亮)

    需求 导航选中的是公司信息 当跳转到公司信息编辑的时候 上面的导航公司信息还是要选中状态 点击导航 回到信息展示页面 下面是我的路由 在vue2里面 使用element ui 像下面这样做是可以的 动态给el menu item的index
  • 第十一届蓝桥杯大赛软件类省赛第二场 Java 大学 B试题 B: 寻找 2020 解答

    说明 以下介绍三种方法 三者的区别仅在于文件读取方式不同 方法1直接把 txt文件复制粘贴到console控制台上 使用了Scanner类 方法2和方法3都是从电脑文件夹读取文件 但是具体读取细节有些差别 方法2使用了io接口的三个包 Fi
  • Lua 数据类型 —— 表

    一 简介 表永远是匿名的 表本身和保存表的变量之间没有固定关系 对于一个表而言 当程序不再有变量指向他时 垃圾收集器会最终删除这个表并重用其占用的内存 Lua 不会进行隐藏拷贝或创建新表 操作的都是指向表的指针 二 元素 1 键 表的键可以