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

在这里插入图片描述

文章目录

  • 官方唯一指定数据结构--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)>


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【飞书】飞书导出md文档 | 飞书markdown文档导出 | 解决飞书只能导出pdf word

一、飞书导出markdown github地址:https://github.com/Wsine/feishu2md 这是一个下载飞书文档为 Markdown 文件的工具,使用 Go 语言实现。 请看这里:招募有需求和有兴趣的开发者,共同探讨开发维护,有兴趣请联系。 二、…

Hive视图

hive的视图 简介 hive的视图简单理解为逻辑上的表hive只支持逻辑视图,不支持物化视图视图存在的意义 对数据进行局部暴露(涉及隐私的数据不暴露)简化复杂查询 创建视图: create view if not exists v_1 as select uid,movie f…

Esp32_Arduino接入腾讯云笔记

ESP32是一款由乐鑫科技(Espressif Systems)推出的双核、低功耗、集成Wi-Fi和蓝牙的单芯片微控制器。它采用了Tensilica Xtensa LX6高性能处理器,具有大量的GPIO引脚、模数转换器、SPI、I2S、UART、PWM、I2C和SD卡接口等功能,可以满…

vue数据单双渲染以及代码讲解

😀前言 本片文章是vue系列第2篇整理了vue的单双数据绑定以及代码讲解 🏠个人主页:尘觉主页 🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力&#x1f…

了解Unity编辑器之组件篇Tilemap(五)

Tilemap:用于创建和编辑2D网格地图的工具。Tilemap的主要作用是简化2D游戏中地图的创建、编辑和渲染过程。以下是一些Tilemap的主要用途: 2D地图绘制:Tilemap提供了一个可视化的编辑器界面,可以快速绘制2D地图,例如迷…

Flask 页面展示文件目录及文件,通过勾选复习框删除

(45条消息) flask 读取文件夹文件,展示在页面,可以通过勾选删除_U盘失踪了的博客-CSDN博客 基本实现 针对上面的功能再优化 项目结构 app.py import os import shutil from flask import Flask, render_template, request, redirect, url_forapp F…

服务器数据恢复-Windows服务器RAID5数据恢复案例

服务器数据恢复环境: 一台服务器挂载三台IBM某型号存储设备,共64块SAS硬盘,组建RAID5磁盘阵列; 服务器操作系统:Windows Server;文件系统:NTFS。 服务器故障: 一台存储中的一块硬盘离…

android app控制ros机器人一

android开发app,进而通过控制ros机器人,记录开发过程 查阅资料: rosjava使用较多,已经开发好的app也有开源的案例 rosjava GitHub https://github.com/ros-autom/RobotCA https://github.com/ROS-Mobile/ROS-Mobile-Android…

Godot 4 着色器 - Shader调试

我之前用OpenCV进行图像相关处理,觉得已经很不错,结合GDI可以实现流畅的动画效果 直到近来用Shader后才发现,着色器更上一层楼,原来这是入了GPU的坑 Shader编程限制很多,各种不支持,看在它性能不错功能炫…

vue 封装一个鼠标拖动选择时间段功能

<template><div class"timeRange"><div class"calendar"><table><thead><tr><th rowspan"6" class"weekRow"><b>周/时间</b></th><th colspan"24"><…

vue中的数据代理

vue数据代理 Vue实现数据代理的核心----Object.defineProperty(); 数据代理 数据代理的定义是&#xff1a;一个对象操作(读\写)另一个对象中的属性和方法。 // 数据代理&#xff1a;通过一个对象代理对另一个对象中属性的操作&#xff08;读/写&#xff09;let obj { x: 100…

vue element ui web端引入百度地图,并获取经纬度

最近接到一个新需要&#xff0c;要求如下&#xff1a; 当我点击选择地址时&#xff0c;弹出百度地图&#xff0c; 效果如下图&#xff1a; 实现方法&#xff1a; 1、首先要在百度地图开放平台去申请一个账号和key 2、申请好之后&#xff0c;在项目的index.html中引入 3、…

Error: Please select Android SDK解决方案(仅供参考)

一、问题描述 今天开始正式接触项目的工作内容&#xff0c;然后从组里的代码仓库里git clone了一份Android Studio项目下来。下好了以后我使用Android Studio打开这个项目&#xff0c;但在尝试编译运行的时候遇到了很多错误。例如&#xff0c;开发环境界面上边用于编译的小锤子…

五,Eureka 第五章

5.3.2 修改pom添加依赖 <dependencies><!--公共部门--><dependency><groupId>cn.bdqn</groupId><artifactId>springcloud-api-commons</artifactId><version>${project.version}</version></dependency><!--e…

Python电商爬虫保姆级入门教程(纯新手向)

图灵Python课堂 长沙图灵教育于2001年开始进入教育行业&#xff0c;立足泛IT类职业教育&#xff0c;以打造高新技术人才为宗旨&#xff0c;专注于提供多层次、个性化的职业技能培训课程&#xff0c;为各行业培养技术开发、应用和管理等岗位的中高端人才&#xff0c;致力于成为…

Python学习笔记-Django框架基础,APP,数据模型,后台管理,路由

一、Django框架简介 Django框架是Python的常用web框架&#xff0c;遵循 MVC 设计模式的框架&#xff0c;采用了MTV的框架模式&#xff0c;即模型M&#xff0c;视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的&#xff0c;即是CMS&…

双虚拟机实现数据库自动备份

FTP的使用&#xff1a; 1.安装FTP 1、检测系统有没有安装ftp&#xff0c;执行命令&#xff1a; rpm -qa | grep ftp若存在用rpm命令移除后再行安装&#xff0c;执行命令&#xff1a; rpm -e vsftpd-3.0.2-9.e17.x86_642、如果没有安装&#xff0c;则在线安装ftp&#xff0c…

Vue2基础八、插槽

零、文章目录 Vue2基础八、插槽 1、插槽 &#xff08;1&#xff09;默认插槽 作用&#xff1a;让组件内部的一些 结构 支持 自定义需求: 将需要多次显示的对话框, 封装成一个组件问题&#xff1a;组件的内容部分&#xff0c;不希望写死&#xff0c;希望能使用的时候自定义。…

关于anki的一些思考

文章目录 通常情况下选择什么模板制卡&#xff1f;一张填空卡片的填空数量到底要多少才合适&#xff1f; 通常情况下选择什么模板制卡&#xff1f; 通常情况是指知识是以一段文字的形式呈现&#xff0c;而不是这些&#xff1a;单词、选择题、成语等&#xff08;这些都可以定制…

openlayers根据下拉框选项在地图上显示图标

这里是关于一个根据下拉框的选项在地图上显示图标的需求&#xff0c;用的是vueopenlayers 显示效果大概是这样&#xff1a; 选中选项之后会跳转到所点击的城市&#xff0c;并且在地图上显示图标温度&#xff0c;这一块UI没设计我就大概先弄了一下&#xff0c;比较丑。。 首先…