Lua基础

table

基本原理:
table是一种特殊的容器,可以向数组一样按照索引存取,也能按照键值对存取。

local mytable = {1,2,3} --相当于数组
local mytable = {[1]=1,[2]=2,[3]=3} --和上面等价
local mytable = {1,2,3,[3] = 4} --隐式赋值会覆盖掉显式赋值
local mytable = {1,2,5,a=9,b="bo"} --支持索引存储,也支持键值对存储
print(mytable[4])--输出为nil,键值对存储不能用索引访问
print(mytable.a) --正确访问方式
mytable.id = "1001" --不用事先定义,使用的时候直接赋值,类似python
--我们收数据的时候只用收table一种数据类型就可以了,约定好里面有什么数据后直接取即可
mytable.userdata = {atk = 15, def = 20} --table可以存放很多数据类型,并且可以嵌套
function mytable:test(p)print(p)print(mytable[1])
endfor i,v in  pairs(mytable) do  --遍历方式,输出的是索引和内容,或者键值对,忽略nil项print(i)print(v)
end
for i,v in ipairs(mytable) do  --遍历方式,输出的是索引和内容,并且不能遍历键值对,并且遍历索引时遇到nil会停止输出print(i)print(v)
end
if next(mytable) == nil then --next第二个参数是索引位,判断索引位的下一位,如果为空就判断第一位print("为空")
endprint(#mytable)  --判断table长度,但注意table里面不能有nil,否则长度计算会在遇到nil的地方停止

底层实现:
table:底层实现分数组部分和哈希表部分。数组部分,从 1 开始做整数数字索引,这可以提供紧凑且高效的随机访问;数组部分存储在 TValue *array 中,其长度 信息存储在 int sizearray 中。哈希表存储在 Node *node,哈希表的大小用 lu_byte lsizenode 表示,lsizenode 表示的是 2 的几次幂,而不是实际大小,因 为哈希表的大小一定是 2 的整数次幂。哈希冲突后,采取开放地址法,应对 hash碰撞。每个 Table 结构,最多会由三块连续内存构成:
(1) 一个 table 结构
(2) 一块存放了连续整数索引的数组
(3) 一块大小为 2 的整数次幂的哈希表

string底层

Lua 中的字符串(string)底层实现使用了一种叫作"短字符串优化"(Short String Optimization)的策略。该策略基于以下两种情况来存储字符串:

短字符串:长度小于等于 40 字节的字符串会直接存储在 Lua 内部的字符串对象中,而不需要额外的内存分配。这种情况下,字符串的数据会被直接存储在字符串对象的数据字段中。

长字符串:长度超过 40 字节的字符串则会分配额外的内存空间来存储字符串数据。Lua 使用一个单独的内存块来存储长字符串的数据,并在字符串对象中存储指向该内存块的指针。

无论是短字符串还是长字符串,Lua 的字符串都是不可变的(immutable)。这意味着一旦创建了一个字符串,就不能再修改它的内容。如果需要对字符串进行修改,必须创建一个新的字符串。

Lua 的字符串实现具有一些优点和注意事项:

  • 节约内存:短字符串直接存储在字符串对象中,无需额外的内存分配,节约了内存空间。长字符串使用单独的内存块存储,可以避免字符串占用过多的 Lua 内存。

  • 高效性能:由于字符串不可变,可以在多个 Lua 值之间共享相同的字符串对象,避免了重复的字符串复制操作,提高了性能。

  • 注意拼接操作:由于字符串不可变,每次对字符串进行拼接操作都会创建一个新的字符串对象。如果需要频繁进行字符串拼接操作,可能会导致大量的内存分配和对象创建,影响性能。在这种情况下,可以使用 Lua 中的字符串缓冲区(如 table.concat 函数)或者考虑使用 LuaJIT 提供的 FFI 接口来进行高效的字符串拼接。

元表

local mytable = {1,2,3}
local mymetatable = {__index = {b=6,c="c"}  
}
mytable = setmetatable(mytable, mymetatable)  --元表扩展了普通表的功能
getmetatable(mytable)  --获取元表
print(mytable.c)  --table里面没有的话会查找元表中的index来调用local mymetatable = {__index = function(table,key)   --访问table中没有的元素调用元表中的indexif key == "b" thenreturn "hello"elsereturn nilendend  --如果index是一个方法__newindex = function(table,key)    --给table和元表中没有的数组元素赋值或给一个变量赋值会执行newindexprint("被调用")return "NoValue"end__call = function(mytable, newtable)  --把元表当做方法(函数)使用的时候调用callsum = 0for i = 1, #mytable do sum = sum + mytable[i]endfor i = 1, #newtable do sum = sum + newtable[i]endreturn sumend__tostring = function(mytable)     --想要直接输出这个表的时候调用return #mytableend__add = function(mytable, newtable)  --两个表进行相加操作的时候调用for i = 1, table.maxn(newtable) dotable.insert(mytable, table.maxn(mytable)+1,newtable[i])endreturn mytableend}
mytable = setmetatable({1,2,3}, mymetatable)
function mytable:test(p)print(p)
end
print(mytable.b)  --会调用index里面的方法输出hello
mytable.c = 10    --设置没有定义的变量会触发__newindex,一般里面做一些报错提醒
mytable[1] = 6    --已经存在的数组元素,不会触发__newindex
mytable[5] = 666  --不存在的数组元素,会触发__newindex
newtable = {10,20,30}
print(mytable(newtable))  --调用__call
print(mytable)       --调用__tostring
mytable = mytable + newtable
print(mytable)---查找和赋值不调用index和newindex函数的方法
print(rawget(mytable ,mytable.w))  --输出的是nil
rawset(mytable,"w",1)   --设置不存在的变量不会调用newIndexmytable:test(5)           --这两种调用方式等价,冒号是一个语法糖
mytable.test(mytable,5)

模块

一个文件想要用另外一个文件的变量,就要用到require。但是如果我们不想每次使用都require,我们可以把lua文件定义成module,这样只需要require一次加载进来,就能在所有文件中访问这个文件的变量。
普通用法

require("math_func")
local ret = math_abs(-7)
print(ret)

定义Module的方式:

module("device",package.seeall)function get_device_name()return "guest9527:
end
local name = device.get_device.name()

接口

如果我们不想把一个lua文件中的所有变量都暴露出去,我们可以在文件中定义一个table作为接口,把所有变量设为local,把想要暴露的添加到table中,然后返回即可。

function math_abs(value)if(value < 0) thenreturn -valueendreturn valueend
function math_vec_length_2(vec)return vec.x * vec.x + vec.y - vec.y
end
function _test_func(...)print("test")
end
local list = {abs = math_abs,lenth = math_vec_length_2,test_func = _test_func,
}return list

lua的数据类型

table
function
nil
boolean
number:包括整数,浮点数等
string

userdata:userdata类型主要用来表示在C/C++中定义的类型,即用来实现扩展lua,这些扩展代码通常是用C/C++来实现的。对lua 虚拟机来说userdata只是提供了一块原始的内存区域,可以用来存储任何东西,并且在lua中userdata没有任何预定义的操作。注意这块分配的额外内存是由Lua垃圾收集器来管理的,无须关心起释放等情况。
thread:线程
注意:数据类型不是固定了,一个数据赋值了整型之后,也可以赋值字符串。
注意:函数也是变量的一种,可以随意赋值给变量
注意:字符串之间的拼接用…

local a = 5
print(type(a))  --打印类型
foo2 =function foo(x)  --函数的赋值print(x)end
foo2(x)

点和冒号的区别

冒号隐式地传递了一个调用这个函数的表的示例进去,可以省略一个参数。

local a = {}
--下面两个函数等同
function a.test(self,a,b)  --这里self必须传进去本身才行print("atest",self)
end
function a:test(a,b)print("atest",self)  --冒号包含了self机制
end

两者不能混着用,如果定义的是冒号,用的时候是点,就会导致找不到self而报错。

闭包

语法域:函数可以嵌套在另一个函数中,内部函数可访问外部函数的局部变量,这样可以用来实现面向对象的编程
闭包:lua编译一个函数的时候,会生成一个原型prototype,包含了函数体对应的虚拟机指令,函数体中的常量,调试信息。运行的到函数的时候会创建一个新的数据对象,对象中包含了响应函数原型的引用和一个数组,包含了所有upvalue的引用(传进来的值),这个数据对象称为闭包。
注意:lua支持函数有多返回值

function f1(n)local fuction f2()print(n)endreturn f2
endg1 = f1(2021)
g1()
g2 = f1(2022)
g2()function create(n)local function foo()local function foo1()print(n)endlocal function foo2()n = n + 10endreturn foo1,foo2endreturn foo
end
f0 = create(2021)
f1,f2 = f0()
g1,g2 = f0()
f1()
f2()
g1()
g2()
f1()--闭包可以作为高阶函数的参数
table.sort(t,function(t1,t2) return t1.param > t2.param end)
--重写(类似面向对象),可以用来添加验证
local oldOpen = io.open
local accessOk = function(filename,mode)--方法体end
io.open = function(filename,mode)if accessOk(filename,mode) thenreturn oldOpen(file,mode)elsereturn nil,"校验失败"endend--实现迭代器
function values(t)local i = 0return function() i=i+1 return t[i] endend
t = {1,2,3,4,5,6}
iter = values(t)
print(iter())
print(iter())
print(iter())

C#和lua的相互调用

c语言可以和lua直接通信,lua就是c语言开发的,C#要和lua通信,需要先调用C语言,C语言再调用lua,Xlua插件封装了C#调用C语言的接口。
C 调用 Lua 实际上是:由 C 先把数据放入栈中,由 Lua 去栈中取数据,然后返回数据对应的值到栈顶,再由栈顶返回 C。
Lua 调 C 也一样:先编写自己的 C 模块,然后注册函数到 Lua 解释器中,然后由Lua 去调用这个模块的函数。
Lua虚拟栈:从底往上是1到n,从顶往下时-1到-n,lua里面用到的数据类型都可以入栈

Lua实现只读表

local readOnly
readOnly = function(t)for k,v in pairs(t) doif type(v) == "table" thent[k] = readOnly(v)endendlocal nt = {}local mt = {__index = t,__newindex = function(t,key,value)error("this is a readonly table")end}setmetatable(nt,mt)return nt
endlocal a = {x=1,y=2}
a = readOnly(a)
a.x = 3 --错误

当我们对readOnly的table进行赋值会调用newIndex函数,从而抛出错误

Lua GC

从Lua 5.1开始,采用三色增量标记清除算法。好处:它不必再要求GC一次性扫描所有的对象,这个GC过程可以是增量的,可以被中断再恢复并继续进行的。3种颜色分类如下:

白色:当前对象为待访问状态,表示对象还没有被GC标记过,这也是任何一个对象创建后的初始状态。换言之,如果一个对象在结束GC扫描过程后仍然是白色,则说明该对象没有被系统中的任何一个对象所引用,可以回收其空间了。

灰色:当前对象为待扫描状态,表示对象已经被GC访问过,但是该对象引用的其他对象还没有被访问到。

黑色:当前对象为已扫描状态,表示对象已经被GC访问过,并且该对象引用的其他对象也被访问过了。当GC完后被重置为白色。
伪代码:

每个新创建的对象颜色为白色//初始化阶段
遍历root节点中引用的对象,从白色置为灰色,并且放入到灰色节点列表中//标记阶段
当灰色链表中还有未扫描的元素:从中取出一个对象并将其标记为黑色遍历这个对象关联的其他所有对象:如果是白色:标记为灰色,加入灰色链表中//回收阶段
遍历所有对象:如果为白色:这些对象都是没有被引用的对象,逐个回收否则:重新加入对象链表中等待下一轮的GC检查

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

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

相关文章

内衣迷你洗衣机什么牌子好?选购内衣裤洗衣机的方法

在如今的这个年代&#xff0c;大多数的用户由于种种原因&#xff0c;连洗自身的内衣裤以及袜子都不想洗。然而内衣裤洗衣机作为近来比较火的小家电&#xff0c;网友的评价褒贬不一&#xff0c;有人说“买来就是鸡肋&#xff0c;用起来不方便”&#xff0c;“也有人买了后直呼真…

力扣740. 删除并获得点数(动态规划)

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;你可以对它进行一些操作。 每次操作中&#xff0c;选择任意一个 nums[i] &#xff0c;删除它并获得 nums[i] 的点数。之后&#xff0c;你必须删除 所有 等于 nums[i] - 1 和 nums[i] 1 的元素。 开始你拥有 0 个点…

基于BP神经网络的风险等级预测,BP神经网络的详细原理,

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数, BP神经网络的传递函数 代码链接:基于BP神经网络的风险等级评价,基于BP神经网络的风险等级预测(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.n…

对一个金融风控测额公式的理解(1)

目录 公式&#xff1a;&#xff08;近3个月回款总额/过去3个月的FBA平均库存价值&#xff09;*最近FBA的库存价值*过去13周FBA发货比例 详细讨论一下这个&#xff1a;&#xff08;近3个月回款总额/过去3个月的FBA平均库存价值&#xff09; 既然&#xff08;近3个月回款总额/…

第十八届黑龙江省赛(K dp)

链接&#xff1a;The 18th Heilongjiang Provincial Collegiate Programming Contest Problem K. Turn-based Game 题意 主角有 A A A 血量&#xff0c;每只怪物有 B B B 血量&#xff0c;每个单位每次进攻伤害为 1 1 1&#xff0c;每个单位血量低于等于 0 0 0 判定为死…

MacOS使用PF实现iptables的端口转发功能

目录 准备web服务通过pf实现端口转发其他命令参考文章 准备web服务 使用Flask启动一个简单的web服务 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello World!if __name__ __main__:app.run(port5000)浏览器访问&#xff1a;http:/…

mybatis plus框架@TableField注解不生效问题及解决方案

目录 一、问题描述二、解决方案三、关于TableField注解失效原因的思考四、Mapper接口LambdaQuery方法调用过程梳理1、Mapper接口调用实际上使用的是动态代理技术2、mybatisplus对查询的单独处理3、findOne实际上还是要查询List4、mybatis接口上下文信息MappedStatement5、myba…

EasyCVR智能边缘网关用户信息泄漏漏洞

EasyCVR智能边缘网关用户信息泄漏漏洞 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: title"EasyCVR" 漏洞复现1. 构造poc2. 获取管理员账户密码3. 登录后台 免责声明 仅用于技术交流,目的是向相关安全人员展示漏洞利用方式,以便更好地提高网络安全意识和技术水平…

办公必备神器:如何用AI快速生成年终总结PPT?

2023年已经步入尾声&#xff0c;今年的销售业绩如何&#xff1f;用户同比增长率是否达到预期&#xff1f;部门年度API完成情况&#xff1f;新开发的项目进展如何&#xff1f;品牌全球计划在各区域市场的部署进展&#xff1f;…… 每年年底&#xff0c;不论是纵横全球的大企业&…

开发环境配置之Linux安装golang

Linux安装golang 目录 1. 下载Go发行版2. 配置工作空间3. 版本升级 1. 下载Go发行版 从官方地址&#xff1a;https://golang.org/dl/ 上下载合适的 二进制发行版 可以使用wget、curl等工具下载具体的go的发行版。 wget https://go.dev/dl/go1.21.3.linux-amd64.tar.gz接着…

Android---底层剖析 Window、Activity、View 三者关系

对于一个 Android 工程师来讲&#xff0c;或多或少都听说过 Window 的概念&#xff0c;并且隐约感受到它在 Activity 和 View 之间应该发挥着某种连接的作用。但如果要说出这三者之间的关系&#xff0c;多数 android 工程师都不知道从何下手。 Activity 的 setContentView Ac…

教研成果登记网站建设开发原理,齿轮加工刀片

成都工具研究所有限公司的前身是成都工具研究所&#xff0c;于1956年创建于北京&#xff0c;是原机械工业部的直属研究所&#xff0c;是我国机械工业的综合性工具科研机构。公司ctri.com.cn 公司主要从事精密切削工具、精密测量仪器以及表面改性处理技术的技术研究、产品开发和…

VScode远程连接错误:进程试图写入不存在的管道

使用VScode连接树莓派时&#xff0c;出现远程连接错误&#xff1a;进程试图写入不存在的管道 解决方案&#xff1a; &#xff08;1&#xff09;可以进入config所在文件夹&#xff0c;删除文件 &#xff08;2&#xff09;无法解决的化尝试下述方法 输入 Remotting-SSH:Settin…

FreeRTOS-任务通知

一.任务通知的相关API 1. vTaskNotifyGive(): 用于给指定任务发送通知。 void vTaskNotifyGive( TaskHandle_t xTaskToNotify );参数说明&#xff1a; xTaskToNotify: 被通知的任务的句柄。返回值&#xff1a; 无。2. ulTaskNotifyTake(): 用于等待并接收任务通知。 uint32_…

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮

自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 自定义表格的表头根据后端的数据进行筛选是否进行自定义表头添加按钮 <template><div class"box"><el-table :data"msgMapList" border class"table">&l…

Java入门篇 之 逻辑控制(练习题篇)

博主碎碎念: 练习题是需要大家自己打的请在自己尝试后再看答案哦&#xff1b; 个人认为&#xff0c;只要自己努力在将来的某一天一定会看到回报&#xff0c;在看这篇博客的你&#xff0c;不就是在努力吗&#xff0c;所以啊&#xff0c;不要放弃&#xff0c;路上必定坎坷&#x…

k8s约束调度其二

一&#xff0c;Pod亲和性与反亲和性 调度策略匹配标签操作符拓扑域支持调度目标nodeAffinity主机In, NotIn, Exists,DoesNotExist, Gt, Lt 否 指定主机podAffinityPodIn, NotIn, Exists,DoesNotExist是Pod与指定PodpodAntiAffinityPodIn, NotIn, Exists,DoesNotExist是Pod与指…

java8利用Stream方法求两个List对象的交集、差集与并集(即:anyMatch和allMatch和noneMatch的区别详解)

1、anyMatch 判断数据列表中是否存在任意一个元素符合设置的predicate条件&#xff0c;如果是就返回true&#xff0c;否则返回false。 接口定义&#xff1a; boolean anyMatch(Predicate<? super T> predicate); 方法描述&#xff1a; 在anyMatch 接口定义中是接收 P…

c++ Vector 学习

vevtor 是c 中自带得动态数组&#xff0c;dynamic array array can hold different values/objects of same type 可以装不同得类型或者对象 dynamic size can be changed at runtime 可以运行得时候改变 要使用的话&#xff0c;先引入 #include <vector> std::vector…

Kafka基本原理、生产问题总结及性能优化实践 | 京东云技术团队

Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的&#xff08;replica&#xff09;&#xff0c;基于zookeeper协调的分布式消息系统&#xff0c;它的最大的特性就是可以实时的处理大量数据以满足各种需求场景&a…