希望能帮助到那些lua的初学者,更好的理解和使用lua这门语言
lua作为一个使用寄存器虚拟机的语言,他需要实现如下几个部分:
1. 将源代码编译程虚拟机可识别执行的字节码
2. 为函数准备调用栈
3. 内部维持一个IP(指令指针)来保存下一个将执行的指令地址
4. 模拟一个cpu的运行,循环拿出ip指向的字节码,根据字节码进行解码,然后执行字节码
虚拟机有两种不同的实现方式,基于栈的虚拟机和基于寄存器的虚拟机,lua是第一个基于寄存器的虚拟机,那么我会讲一下这两种虚拟机的不同,并做一下分析
基于栈的虚拟机:
在基于栈的虚拟机中,字节码的操作数在栈顶弹出,在执行完成之后再压入栈顶的,在我们的内存中,栈作为一个独立的内存区域,我们去计算一个数据的时候,基于栈的虚拟机,会首先把需要的数据压入栈顶,在计算完结果后,把之前压入栈顶的数据push掉后,把结果在压入栈顶,这个过程在计算一个类似1+2=3的方法时,实际需要如下四个步骤:
1. Pop 1
2. Pop 2
3. ADD 1,2,result
4. Push result
可以看到,执行一条假发需要四条字节码,前面几条指令用来准备数据,将数据压入栈,这就是设计上的缺陷。但优点是,指令中不需要关心操作数的地址,在执行操作数据已经把数据放在栈顶了
基于寄存器的虚拟机
与基于栈的虚拟机不同,在基于寄存器的指令中,操作数是放在“cpu寄存器”中,这个并不是物理意义上的寄存器,因此同样操作不再需要push,pop指令,取而代之的是在字节码中带上具体操作数所在的寄存器地址,对比基于栈的虚拟机,由四条指令降低为一条,但缺点是程序需要关注操作数所在的位置
之所以讲lua虚拟机一些基础原理,是为了接下来有助于帮助我们在使用lua时候有更深刻的理解
我从15年入行,17年才接触lua,从经验来说,只能算个新兵,同时这是我第一篇博客,我希望以一个新兵的视角给大家在学习lua带来帮助
Lua语法篇:
lua有很多数据结构
Lua 数据类型
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。值可以存储在变量中,作为参数传递或结果返回。
Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。
数据类型 |
描述 |
nil |
这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean |
包含两个值:false和true。 |
number |
表示双精度类型的实浮点数 |
string |
字符串由一对双引号或单引号来表示 |
function |
由 C 或 Lua 编写的函数 |
userdata |
表示任意存储在变量中的C数据结构 |
thread |
表示执行的独立线路,用于执行协同程序 |
table |
Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。 |
以上是
https://www.runoob.com/lua/lua-data-types.html 摘抄的引用
这里的userdata,你可以理解为一个内存地址,实际上对于lua虚拟机,table实际上也是一块内存地址,那么我谈一谈table这种数据结构吧,table里面的key有两种类型,一种是int类型,一种是其他类型,这篇博客会讲述实现原理:
https://blog.youkuaiyun.com/zr339361504/article/details/52432163
理解完lua table的实现,我们聊一聊我们常见的:和.这两个标识符,我引用网上一篇博客做解释
1. 原文地址https://www.cnblogs.com/xzxdm/p/6980267.html
lua的语法很简单,太简单了,所以lua就复杂了
两个点与一个点有什么区别呢?
一个点用来定义和取得一个变量,这个变量可能是个函数
两个点用来定义和调用一个函数,两个点会自动传入“调用者”这个table自身
先看简单的:
c = {a = 1, b = 2}
function c:foo()
print(self.a,self.b)
end
这里,c这个table定义了一个foo函数,用两个点定义的,在foo函数第一个参数的地方自动传入了c自身,然后调用一下
c:foo()
输出1 2
也可以这样,一个点调用函数,手动传入table:c.foo(c)
输出也是一样的
下面看复杂一点的:
两个点会自动传入调用者本身,但是他仅仅只会传入调用者本身,他没有一个点灵活,这个怎么理解?看代码
c = {a = 1, b = 2}
c.foo = function(c) print(c.a,c.b) end
d = {}
d.foo2 = c.foo
d:foo2()
输出为:nil nil
解释下上面的代码:
首先创建一个table,然后定义一个函数foo,这个函数访问了table中的a和b两个变量
然后创建了另一个table,b
在b中定义一个变量foo2,赋值为c这个table中的foo函数
然后调用d这个table中的foo2函数,输出为nil nil
因为d是两个点调用的foo2,那么会自动吧d本身传入函数的第一个参数,那么函数的运行就是这样的:
function (d)
print(d.a,d.b)
end
d<