Lua基础学习
要学习tolua++的使用,首先也得先学会lua的基本语法和lua与c/c++之间的接口调用。本次总结意在把lua的一些基本的用法总结归纳一下,好让大家可以在短时间内对lua有一个简单的了解,达到可以看懂lua代码的目的。
注:
注释:单行注释:--
多行注释:--[[ --]]
lua大小写敏感
1. 基本类型
1.1 nil
它就相当于c++里边的NULL,但又与NULL不同,lua中的全局变量变量如果没有赋初值,则它的值就默认等于nil,如果想要删除一个全局变量变量,则可以给它赋值nil。
1.2 booleans
它的取值跟c++一样,有true和false两种。但是在lua中有一个特别的地方,在判断语句的时候,除了false和nil为假,其它的值都为真,这点c++程序员应该格外注意,0和空串也为真。
1.3 numbers
在lua中number代表实数,他强大的可以代表任何你能想象到的数字(玩笑开大啦),在应用中去探索吧。例:整数、浮点、指数似乎还有复数等。
1.4 strings
lua中的string就类似c++中的const char[],不过人家是通过lua来自动分配内存和释放内存的。另外注意那个const,它的值是不允许修改的;
它支持转义字符,类似c++的转义字符;
lua会自动在string和numbers之间自动进行类型转换,当一个字符串使用算术操作符时,string就会被转成数字,如果string中的内容并非number的时候,可会报错哦;
在lua中字符串的连接符是..,如果要连接的是数字,则要在..和数字间留一个空格;
另外lua还提供tonumber()和tostring()函数,支持数字和字符串间的转换,不过在字符串转换数字的时候,如果字符串不是正确的数字tonumber()会返回nil。
1.5 functions
在lua中,函数也可以作为变量保存,可以作为函数的参数和返回值,了解到这个,你就可以在你的lua代码中发挥自己的想象去实现一些强大的功能啦。
1.6 userdata
顾名思义,就是用户自己定义的类型,其实就是在lua和c++交互过程中,c++定义的 类型。
2. 表达式
2.1 算数运算符
跟c++一样,加减乘除啥的。
2.2 关系运算符
跟c++类似,就是!=换为~=。
2.3 逻辑运算符
这个可比较特别哦,要多加注意,lua的逻辑运算符有not、and、or;
lua中只有false和nil为假,其它都为真;
not a: a为false,值为true,a为true,值为false;
a and b: 如果a为false,则取a值,否则取b值;
a or b: 如果a为true,则取a值,否则取b值;
c++中的三目运算符a?b:c在lua中的实现:(a and b) or c。
2.4 连接运算符
.. -- 这个前边介绍过,就是连接两个字符串
2.5 优先级
类似c++,按老套路用就行
2.6 表的构造
这是lua的重头戏,它的构造函数是{}。
table = {} -- 创建一个空表
表里边可以存放任意类型的成员,就把它当做一个c++的类即可,以下聚几个例子
test = {“a”,”b”,”c”,”d”,”e”,”f”,”g”}
print (test[4]) -- d // 这里注意,lua的下标操作是从1开始计算的
test = {x=1,y=2,z=3}
print (test.x,test.y,test.z) -- 1 2 3
test[1] = "a"
test1 = {"b","c"}
test1.a = test
print (test[1],test.x,test.y,test.z) -- a 1 2 3
print (test1.a[1],test1.a.x,test1[1]) -- a 1 b
更多细节请参照lua官网
3. 基本语法
3.1 赋值
lua可以对多个变量同时赋值,各变量和值用逗号分隔,赋值语句右边的值会依次赋给左边的变量;
当变量个数比值多时,多出的变量会赋值nil;
当变量个数少于值时,多余的值会忽略;
例:
x,y = y,x -- 交换x和y的值
a,b,c = 0,1 -- a=0,b=1,c=nil
a,b = 3,2,1 -- a=3,b=2
3.2 局部变量
lua使用local创建局部变量,它的作用域就跟c++类似,不过它没有{},取而代之的是do..end,如果想要设置一个局部变量,则可以将它定义在do..end当中;
lua中使用局部变量有两个好处:
- 避免命名冲突
- 访问局部变量的速度比全局变量快
例:
do
local a = 2
b = 4
print (a,b) -- 2 4
end
print (a,b) -- nil 4
3.3 控制语句
3.3.1 if语句
if conditions then
then-part
end;
if conditions then
then-part
else
else-part
end;
if conditions then
then-part
elseif conditions then
elseif-part
.. --->多个elseif
else
else-part
end;
3.3.2 while语句
while condition do
statements;
end;
3.3.3 repeat-until
repeat
statements;
until conditions;
这个可能比较眼生,其实类似c++的do..while语句,即运行statements直到conditions为真。
3.3.4 for循环
3.3.4.1 数值for循环
for var=exp1,exp2,exp3 do
loop-part
end
for将用exp3作为step从exp1(初始值)到exp2(终止值),执行loop-part。其中exp3可以省略,默认step=1.
3.3.4.2 范型for循环
遍历表
for k in pairs(t) do print(k) end -- 遍历表t中的所有元素
for i,v in ipairs(a) do print(v) end
--遍历表a,i为其索引,v为其值。
3.3.5 break和return
这个语法与c++类似,break是用来退出控制语句,return是用来退出函数的。
注:在lua中,break和return必须在一个块得结束部分出现,即它的后边出现的必须是end、else、until,如果真的想要在某个语句位置使用它们,可以显式的使用do..end来包含它们实现想要的功能。例:do return end;
4. 函数
4.1 函数的定义
function name (param)
return value
end;
4.2 多返回值
lua是允许返回多个值的,如果函数有多个返回值,则对变量的赋值按照3.1赋值里边规定的方式赋值。
例:
function foo0 end
function foo1 return 'a' end
function foo2 return 'a' 'b' end
x,y = foo2() -- x='a', y='b'
x = foo2() -- x='a', 返回值'b'废弃
x,y,z = 10,foo2() -- x=10, y='a', z='b'、
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x='a', y=nil
x,y,z = foo2() -- x='a', y='b', z=nil
4.3 可变参数
lua函数可以接受可变数目的参数,和C语言类似在函数参数列表中使用三点(...)表示函数有可变的参数。lua将函数的参数放在一个叫arg的表中,除了参数以外,arg表中还有一个域n表示参数的个数
例:
printResult = ""
function test(...)
print ("haveing " .. arg.n .. " param")
for i,v in ipairs(arg) do
printResult = printResult .. tostring(v)
end;
print (printResult)
end
test('a','b','c','d','e')
结果:
haveing 5 param
abcde
4.4 命名参数
lua的调用过程中,参数是依次把实参传递给相应的形参的。但如果有时候我们很难记清参数的前后顺序,这个时候就可以使用命名参数。顾名思义,就是为每个参数起一个名字,调用的时候,只需要为这个名字的参数赋值即可。
例:
function rename (arg)
return os.rename(arg.old, arg.new)
end
rename(old="temp.lua", new="temp1.lua") –调用的时候为命名参数赋值
4.5 闭包
首先明确一个概念,词法定界。当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界
所谓“闭包”,官方解释指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
是不是有点糊涂呢?举个例子:
function newCounter()
local i = 0
return function() -- 无名函数
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
c2 = newCounter()
print(c2()) --> 1
print(c1()) --> 3
print(c2()) --> 2
这段代码有两个特点,1. “匿名函数”嵌套在函数newCounter内,2. 函数newCounter把“匿名函数”返回了。
在执行完c1 = newCounter()后,其实c1指向的是“匿名函数”,当我们执行c1的时候,就可以操作函数newCounter的局部变量i,这个i我们称之为外部的局部变量(external local variable)或者upvalue。我们再次声明一个变量c2= newCounter()后,c1和c2其实是建立在同一个函数上的,但是他们的局部变量i确是两个不同的实例,即我们创建了两个闭包。就是说:当函数newCounter的内部函数(即上例的“匿名函数”)被函数newCounter外的变量c1引用的时候,就创建了一个闭包。
闭包的应用场景:
- 保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
- 在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
4.6 非全局函数
lua中函数可以作为全局变量也可以作为局部变量
1. 表和函数放在一起
Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end
2. 使用表构造函数
Lib = {
foo = function (x,y) return x + y end,
goo = function (x,y) return x - y end
}
3. lua提供的另一种语法方式
Lib = {}
function Lib.foo (x,y)
return x + y
end
function Lib.goo (x,y)
return x - y
end
当我们将函数保存在一个局部变量内时,我们得到一个局部函数,也就是说局部函数像局部变量一样在一定范围内有效。定义局部函数的两种方式:
local f = function (...)
...
end
local function f (...)
...
end
看如下代码:
local fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1) -- 此处lua不能识别fact,因为是局部函数,lua不能识别
end
end
修改为先声明,如下:
local fact
fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1)
end
end