lua简介

C++底层核心模块,暴露核心接口给lua脚本层,网络的收发都在c++层完成,本书简述lua解释器的实现原理,工业级脚本语言

特性:简洁高效可移植可嵌入可扩展

纯C编写

Lua的数据结构、Lua虚拟机、Lua的其他内容

我缺少的知识:词法分析、语法分析、递归下降分析、BNF规则

Lua代码是解释成lua虚拟机能识别的字节码而运行的

  • 翻译成字节码
  • 字节码装载到虚拟机执行

Lua是有宿主系统的

Lua采用一种通用的数据类型来表示所有的类型,Lua只有字符串和表两种基本的数据结构

一种通用的数据类型:lua_TValue

  • 一个字段存储数据类型
  • 存储不同的数据类型的数据(联合体)

commonHeader+union,lua还要标出处理GC的对象

配图:

字符串

每当创建字符串时,会先查找内存中是否有一份相同的字符串数据,如果存在就直接复用,将引用直接指向字符串数据,否则就重新创建一份数据,这样在进行字符串数据比较和查找时性能会提升不少,系统内部维护了一个全局的字符串的表用来存放字符串(LUA虚拟机使用一个散列桶来管理,global_state的strt),比较时可以直接比较字符串散列值,这样也是有空间优化,相同字符串只有一份数据

应当尽量少的使用字符串连接符,每次使用都会创建一个新的字符串,大量重复的相同字符连接可以用一个table缓冲区一个字符一个字符的缓存起来,然后再调用table.concat将其全部连接

Table

有数组和散列表部分,唯一的要求就键值不能为nil

数组从1开始索引,内涵散列桶数组起点和终点的指针还有元表,意思0和负数的索引都是哈希表里的内容,如果数字的很大,超过了数组长度则是在散列表里面存

存的数据有可能在数组或者在散列表部分

查找数据:使用key来查找。我们看这个key是否为正整数且他是否大于0且小于等于数组长度,在则在数组中查找,不在则跑到散列表去查

设置数据:set setnum setstr三个set数据的函数先找对应的key,找不到则内部是调用一个newkey函数分配一个新key,大小不够会重新散列

个人实践规律:取长度符号#

取长度,只对表的序列部分进行,序列指的是表的一个子集,

当既有数组部分又有散列表部分,优先取数组部分长度,

当只有数组部分时候取数组的长度

(#{1,2,3,nil,4,5,6,} == 6)

当散列表的key和数组的Index一致的时候,遇到[num] = nil的时候便停止计数

(#{[1] = 10,[2]=20,[3]=nil,[4]=60} ==2)

(#{[1] = 10,[2]=20,[3]=32,[5]=60} ==3) 缺少4

当只有散列表部分时,取key从1开始的最大正整数

(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[45]=60} == 0)

(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[1]=60,[2]=899} == 0)

一般要规避重新散列操作,一般通过只使用数组部分、预分配等方式来避免重新散列

尽量不要混用数组和散列表部分,一个table最好只放一类数据

lua实现一个队列

网上的版本,用起来,pushright存数据会往数组里的填很多东西,pushleft突破了0,会往哈希表里填东西,如果一直popleft多了则数组部分的头部会被回收吗?推测不会,数组部分的指针指向的数组整体,前面几个元素回收了头部会改变,如果是popright回收数组部分是可以理解的,如果pop的是哈希的部分应该是可以回收的

List = {}
function List.new ()
return {first = 0, last = -1}
end function List.pushleft (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end function List.pushright (list, value)
local last = list.last + 1
list.last = last
list[last] = value
end function List.popleft (list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil -- to allow garbage collection
list.first = first + 1
return value
end function List.popright (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- to allow garbage collection
list.last = last - 1
return value
end

插入、删除时间复杂度 O(1),空间复杂度可能会随着消息变大而变大,O(n)

使用Insert和Remove的版本,空间复杂度是O(1)的,时间复杂度是(n)

关于清空lua table

a = {1,2,3,4,5}

function upDate(t)
print("====")
print(t)
t = {}
print(t)
end upDate(a)
print(a)
print(a[1])

这里设置t = {} 或者 t = nil都不会真的清空table对象 a

只是处理了变量和值之间的关系,t的地址是值传递的,尝试用一个新表的地址给它赋值会出现函数参数值传递,对地址t引用的实际值并不会有影响,但是通过t改动引用table里的实际值是会对a有影响的比如t[1]=999,这里就是通过地址改动到了实际值的区域

我的方法是使用——table套table,其实就是相当于指针的指针

local a = {1,2,3,4,5}
local b = {9,99,999,9999}
function upDate(t)
print("====")
print(t.a)
t.a = nil
--a = nil
print(t.a)
end local ta ={}
ta.a = a
upDate(ta) print(ta.a)
print(a)

这样子ta.a可以便可以正确的赋值为nil了

我实现的一份LuaQueue代码

local LuaQueue = {}
-- pure array table, if you want to iterate use lua "ipairs"
function LuaQueue.New()
return {_length = 0,_maxLength=10,_queue={}}
end function LuaQueue.SetMaxLength(queue,length)
if(queue==nil) then
error("Queue is nil")
end
queue._maxLength = length
end function LuaQueue.GetLength(queue)
if(queue==nil) then
error("Queue is nil")
end
return queue._length
end --push in array last pos O(1)
function LuaQueue.Push(queue,val)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length<queue._maxLength) then
table.insert(queue._queue,val)
queue._length = queue._length+1
else
error("Already reach last pos")
end end --O(n)
function LuaQueue.Pop(queue)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length>0) then
table.remove(queue._queue,1)
queue._length = queue._length-1
else
error("Queue is Empty")
end
end function LuaQueue.GetData(queue)
if(queue==nil) then
error("Queue is nil")
end
local data={}
if(queue._length>0) then
for _,v in ipairs(queue._queue) do
table.insert(data,v)
end
return data
else
print("Queue is Empty")
end
end
function LuaQueue.ClearData(queue)
if queue == nil then
error("Queue is nil")
end
queue._queue = {}
queue._length = 0
end
--[[Example:
local testQueue = LuaQueue.New()
LuaQueue.Push(testQueue,10)
LuaQueue.Push(testQueue,20)
LuaQueue.Push(testQueue,30)
LuaQueue.Push(testQueue,40) local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue) local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue)
LuaQueue.Push(testQueue,909)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
LuaQueue.ClearData(testQueue)
--]]

Lua设计与实现--读书笔记的更多相关文章

  1. Linux内核设计与实现 读书笔记 转

    Linux内核设计与实现  读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...

  2. 【2018.08.13 C与C++基础】C++语言的设计与演化读书笔记

    先占坑 老实说看这本书的时候,有很多地方都很迷糊,但却说不清楚问题到底在哪里,只能和Effective C++联系起来,更深层次的东西就想不到了. 链接: https://blog.csdn.net/ ...

  3. Redis设计与实现读书笔记——简单动态字符串

    前言 项目里用到了redis数据结构,不想只是简单的调用api,这里对我的读书笔记做一下记录.原文地址: http://www.redisbook.com/en/latest/internal-dat ...

  4. Redis设计与实现读书笔记(二) 链表

    链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...

  5. Redis设计与实现读书笔记(一) SDS

    作为redis最基础的底层数据结构之一,SDS提供了许多C风格字符串所不具备的功能,为之后redis内存管理提供了许多方便.它们分别是: 二进制安全 减少字符串长度获取时间复杂度 杜绝字符串溢出 减少 ...

  6. Redis 设计与实现读书笔记一 Redis字符串

    1 Redis 是C语言实现的 2 C字符串是 /0 结束的字符数组 3 Redis具体的动态字符串实现 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空 ...

  7. 《点石成金-访客至上的web和移动可用性设计秘籍》读书笔记

      简介 作者Steve Krug,惯例先去了解一下本书的作者,发现书中介绍的并不多,百度一下后发现这本书比作者出名.好吧,百度就是这样子,作者自称web可用性咨询师,手上这本书是第三版再版,第一版2 ...

  8. Linux内核设计与实现 读书笔记

    第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...

  9. 《About Face 3:交互设计精髓》读书笔记(一)

    第一章 目标导向设计 当今数字产品的创造过程 市场营销人员对于产品设计过程的贡献,通常局限于需求列表这些需求同用户的实际需要与期望无关,主要在于追赶竞争对手,按照任务清单管理IT资源,以及基于市场调查 ...

随机推荐

  1. Java二进制和位运算,这一万字准能喂饱你

    基础不牢,地动山摇.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BAT的乌托 ...

  2. Linux下关闭和开启IPv6的方法

    确认IPV6是否开启 在Linux下确认IPv6是否已经被启用,可以从三个方面确定. 1.使用ifconfig查看自己的IP地址是否含有IPv6地址. eth0 Link encap:Ethernet ...

  3. csp201909-2小明种苹果续

    /* 定义输入N 二维数组 输出T总数 D掉落棵树 E掉落组数 定义last记录上次掉落的编号,flag=1表示两次连续掉落,不掉落归零 spec=1表示1 2都掉落了,spec=2表示只有1掉落 对 ...

  4. shader效果

    Unity Shader - 消融效果原理与变体 https://www.jianshu.com/p/d8b535efa9db

  5. layaair

    LayaAir之设置反向遮罩镂空遮罩挖洞模式 https://blog.csdn.net/qq_20342915/article/details/100690786 Sprite--新手引导 http ...

  6. [BUUOJ记录] [BJDCTF2020]Easy MD5

    各种关于md5的Bypass操作,都是基本操作,考察数组绕过.弱类型比较绕过以及md5($password,true) ByPass 1.利用md5($password,true)实现SQL注入 F1 ...

  7. 【Go语言入门系列】(九)写这些就是为了搞懂怎么用接口

    [Go语言入门系列]前面的文章: [Go语言入门系列](六)再探函数 [Go语言入门系列](七)如何使用Go的方法? [Go语言入门系列](八)Go语言是不是面向对象语言? 1. 引入例子 如果你使用 ...

  8. HTTP走私

    干货 https://paper.seebug.org/1048/

  9. IDEA编写JavaWeb出现乱码,成功解决!

    使用IDEA写JavaWeb项目时,总会出现编码出错等问题,比如下面这样,页面显示出来一大堆乱码,下面跟着我来操作一下,可以成功解决! 首先在IDEA安装目录下有一个:bin的文件夹,打开后找到如下两 ...

  10. SpringCloud-config分布式配置

    为什么要统一管理微服务配置? 随着微服务不断的增多,每个微服务都有自己对应的配置文件.在研发过程中有测试环境.UAT环境.生产环境,因此每个微服务又对应至少三个不同环境的配置文件.这么多的配置文件,如 ...