Lua学习笔记

来源:互联网 发布:消防工程师题库软件 编辑:程序博客网 时间:2024/06/06 01:26

背景,已经熟练使用C语言.

1,变量

变量:与C相比,Lua的变量没有类型,变量更像是一块内存的名字,内存可以存储任意类型的数据,同时内存也可以扩大,缩小,删除.以上操作由语言本身或编译器中的库完成.
对变量赋值的同时就是对变量的定义,与C类似变量同样有全局与局部的概念.

a = “dfasd” –字符串
print(type(a))
print(a)

a = 23 –数字
print(type(a))
print(a)

if a > 5 then
local a = “local a” –局部变量
print(a)
end

print(a) –全局变量

2,数据类型

除常见的数字,字符串,布尔外,比较有特点的定义了空,表,函数,自定义数据,线程.
空:变量没有分配内存时为空,或者逻辑运算可能为空.
表:一块动态变化的内存,成对的保存变量的索引与变量的值.索引可以是数字,就形成数组(注意数组的索引从1开始);也可以字符串,形成结构体.变量的值同样可以是任何值,索引可以是一种,也可以是多种.元素的个数,可以动态的增加,删除.
函数:与C类似,在C中函数是一个指针,在Lua中,函数可以作变量使用.
自定义数据:与其它语言进行交互时用到.
线程:(todo)

3,运算符

对于不同的数据,有不同的运算符,运算过程类型.
特殊的是:字符串连接,用于把字符串连在一起.table构造式,用于表的创建.
“#”:求表的长度,但只统计索引从1开始,且没有间断的长度,
多重赋值:同时对多个变量进行赋值,即”=”左边可以有多个变量,其变量的值依次按照右边的数依次赋值,如果不够以nil赋值.

4,语句

控制语句与C类型.
不同在于:local专门用来定义局部变量,限定变量的作用范围.
for语句不同,首先是循环变量可以是按数字变化,也可以是依次取表中的变量.按Lua的规定,循环变量不可以在循环中进行修改,否则会出错.

5,函数

函数需要用关键字function进行定义.
输入的参数需要在函数定义时声明,可以是固定个数,也可以是不固定个数.
返回参数不需要声明,同时可以返多个参数,还可以根据需要在不同条件下返回的参数个数不同.
函数的尾调用,在函数return时调用另一个函数,就是尾调用,注意这里指的调用,只是调用,没有其它任何操作.
函数调用时的入口参数,可以按定义时的次序进行赋值,也可以

6,迭代器

迭代器融合了几个方面的内容.
函数:进行迭代的是函数.
尾调用:迭代函数是尾调用结构.
局部函数:尾调用的函数必须是局部函数
变量:迭代过程中,需要保存过程变量,可以用全局变更,也可以用local定义局部变量,在创建迭代器时变量的值会初始化,函数在调用时变量值不会被重置.
迭代器的创建:通过变量赋值的方式创建迭代器
迭代器的调用:以函数方式进行调用.

其实迭代器可以通过语句的组合来完成,使用迭代器可以简化很多语法.

迭代器案例:
function va()
local i = 0 –迭代过程的变量,使用局部变量,在创建迭代器时初始化
return function () i = i + 1 return i end –尾调用局部函数
end

t = va() –创建迭代器,i初始化为0

print(t()) –调用迭代器,i加1,返回1
print(t()) –调用迭代器,i加1,返回2

t = nil –删除迭代器

7,全局变量_G

全局变量_G是一个表,程序中定义的全局的变量,函数,都会自动加入到这个表中.同时这个表中已经预定义了一些变量,函数.例如print函数,type函数
对于_G表内函数的调用不需要指定_G.

8,库与包

与C类似,Lua可以使用别人写好的模块,类似C的库和include.
Lua定义的包就是Lua的源代码文件.具体结构是:首先是一个表,表的名字与文件名相同;包中的变量,函数都必须定义到这个表中;最后用return返回表的名字.这样一包就写好了.注意源代码中local不要直接用,结果会不太一样.在文件的结尾也可以不用return,而是直接对_G[包名],package.loaded[包名]赋值的方式.
使用关键字require引用包.语法是require “包的名字”.Lua在引用包时需要知道包所在的路径,路径信息保存在_G.package.path中,引用后的包都会在_G以及package.loaded表中.要使用包中的元素,语法是:包名.元素名.
去除引用包的方法就是_G.包名 = nil.
模块,感觉模块的用处不大,用表结构嵌套表就可以实现,所以暂时不研究其原理.

//以上大部分,都可以使用结构化的方法进行理解,下面研究一些面向对象的方法

9,表与类

表,对于Lua这个数据类型,表中的元素可以是变量,也可以是函数,如果函数参与处理的变量,除了入口参数,局部变量外,还包括所在的表中的变量,这其实就是类的形式.可以说表具备了面向对象编程中类的概念.但也有很大不同,表在定义时必须已经是一个变量,占用存储空间,而类只是类型,是不占用存储空间的;其次是类中的变量有私密性,表不具备这个特性.
类中的函数操作类中的变量时通过类名,或this,在Lua中也提供类似的语法self.案例:
a = {}
a.x = 23
a.y = 44
function a.fun(self, t)
self.x = self.x + t
end
b = a
b.fun(b,3)
在上面的案例中,使用self,而不是直接使用a的好处是:当我复制表a到b时,表b中的函数fun操作的是表b中的元素.否则操作的依然是表a中的元素.
但以上的用法还有一个问题,就是在调用函数fun时语法是:a.fun(a, 5),即在调用时指定表a.这个问题可以通过字符:来改进,案例如下:
a = {}
a.x = 23
a.y = 44
function a:fun(t)
self.x = self.x + t
end
调用时的语法是a:fun(34)

10,元方法与重构

对于不同的数据类型,都有相应的操作.例如对于数字类型,有加,减,乘,除等操作.这些操作在Lua中称作:元方法,元方法的集合称为:元表.理论上所有数据类型都应该有自己的元表,但是Lua只提供字符串的元表,其它数据类型的元表并不开放,只能通过修改底层C代码来实现.
案例:
a = “1234”
b = a
a = nil
c = {3,4,5}
d = c
c[1] = 9
执行以上代码后,变量b的值是”1234”,但变量d值是nil.原因是对于字符串变量有赋值即”=”这个元方法,而对于表c没有赋值这个元方法.在上面代码”=”的作用仅仅是把d作为c的引用,有人称之为:浅复制.结果是c,d指向相同的内存空间,当执行c[1]=9时,d[1]的值也是9.
如果希望上的赋值操作实现复制的效果,有人称之为:深复制,很可惜Lua并没有提供这个种机制.只能通过代码来自己实现.Lua提供的可以进行重构的元方法是有限的.这里以”+”为案例.这部分类似面向对象中重构的概念.
a = {}
a.x = 1
a.y = 1

b = {}
b.x = 1
b.y = 1

mt = {}
function mt.__add(s1, s2)
local s3 = {}
s3.x = s1.x + s2.x
s3.y = s1.y + s3.y
return s3
end

setmetatable(a, mt) –关联元表
setmetatable(b, mt) –关联元表
到此,变量a,b都已经有了元方法”+”.当执行c = a + b时,c是与a具有相同结构的表,但注意变量c是没有元方法”+”.在实际测试中,变量a,b只需要一个具有元方法就可以进行”+”这个操作,但如果a,b都没有元方法”+”,那结果就会报错.
其时以上过程,我们可以更简化一些,先编写好元方法,同时变量也可以用函数返回值的方式创建,同时在函数内部完成变量结构,以及元表的关联.
可以通过getmetatable查看关联的元表,通过semetatable关联元表,这个函数都定义在_G中,属于Lua预定义的函数.
__index:对表的操作,如果元方法不存在,或访问的元素不存在,都会查找默认的元方法__index,如果__index为nil,返回nil,否则调用__index.如果__index是一个表,就会在这个表中查找元方法.找到就会调用,否则返回nil.同样__index下还可以继续有__index.还有一种情况是,
如果不希望访问__index,可以使用rawget来实现.
__newindex:如果是对表中的元素进行赋值操作,默认情况下如果元素不存在就会在表中增加这个元素.__newindex会在这种情况下代替默认操作.
元表中元方法的存放有一定规则的,以__开头的元方法,是Lua预定义的元方法名字,直接存放在元表中,如果还有其它元方法,元表中的__index必须修改为表类型,其它元方法存放在__index中.如果是对不存在元素的赋值,元方法是__newindex.

11,继承

Lua并没有继承的概念,只有有些特征与继承类似.
当我访问表中一个元素时,过程是这样的,搜索表中是否含有这个元素,如果没有就从元表中查找这个元素,如果元表以及元表下__index也没有.一般情况下就返回nil了.但另外一情况是:当前表的元表,也存在元表,即元表的元表.此时会继续搜索元表的元表,直到找到或搜索结束.
如果把以上过程反过程来,就是这样的.表A被设置为表B的元表,表B又被设置为表C的元表.访问表C中的元素时,先查找表C,再查找表C的元表B,再查找表B的元表A.
这样一来就有继承的特征了.
表A被设置为表B的元表时,表B就继承了表A的方法;表B被设置为表C的元表时,表C就继承了表B以及表A的方法.
如果表B在继承元表A的同时,定义了与元表同名的元方法,这样一来表C在搜索时,会首先在元表B中搜索到元方法,就不会再继续搜索元表A了.此时又具备了重构的概念.
让表A的元素可以成为元方法,需要将表A中元素添加到__index中,可以定义时增加这样一条语法: self.__index = self.
不同于其它面向对象语言,Lua并不提供继承的私密性,即子类可以访问基类的所有元素.
多重继承(todo)

12,并行

13,CAPI

原创粉丝点击