前言:
语言学起来其实相似点很多,简单整理的知识点
目录:
1.使用控制台
2.Lua基础
3.变量
4.运算符
5.控制结构
1.使用控制台
Lua脚本是包含一系列Lua命令的简单脚本(扩展名为.lua的文本文件)。Lua不关注格式,制表符,换行符或者其他让脚本文件更具可读性的转换符号(不过Lua还是需要命令之间的空格符号,用来区别变量和函数调用)
简单的Lua脚本:
for indx = 1,4 do
print("line:",indx )
end
也可以写成:for indx = 1,4 do print("line:",indx ) end
注:
格式化后的脚本更容易阅读,但不改变结果
可以把脚本放在本地文件夹通过dofile命令来在控制台执行脚本,参数是字符串,指定文件的名字和路径。使用dofile命令可以在命令行中运行脚本,如果脚本有什么错误的化,命令行会给出错误信息以便调试。
语法格式:
dofile<"c:\\file_name\\lua_scripts_name.lua">
2.Lua基础
优势:整合C++的模块来扩展自身的功能。
语言定义
不以数字为标识符开头(同C),避免下划线接大写字母(_NAME),因为这种格式是Lua自身保留的(保留字),如_Start。
Lua保留关键字
and local break nil do
not else or elseif repeat
end return false then for
true function until if while
in
变量,常量,函数名的格式和命名规则:
常用全大写和下划线(MY_NAME)
变量第一个字母小写(myVariable)
全局变量第一个字母用小写(gMyGlobal)
函数名第一个字母大写(function MyFunction)
--单行注释
--[[
statements 块注释
--]]
使用技巧:--[[ 或者 --]] 加一个 - 可以重新使用这段代码 ---[[ ---]]
3.变量
在Lua中,变量不需要在使用前声明,这个稍微有些争议。因为不需要声明,所以可以才任何地方引入需要的变量。由于不是显式声明,所以很难追踪变量(不造),或者在另一个函数中用了相同名字的变量而造成数据的混乱。因此,必须小心的使用变量,要保证变量是可追踪的。同样不需要指定变量类型,变量类型取决于给变量赋的值,灵活性较高。
变量赋值:
1.赋值改变
2.改变表域
多个变量同时赋值时赋值变量列表和值列表的各个元素用逗号分开,依次赋值。
a,b=1,2
遇到赋值语句Lua会先计算右边所有的值然后在执行赋值操作,所以我们可以这样进行交换变量的值。
x,y=y,x
当变量个数与值个数不一致时,Lua会以变量个数为基础,采取不足补nil,多的忽略。
例:
a,b,c=0,1 --->0,1,nil
a,b,c=0,1,2,3 --->0,1,2
多值赋值常用来交换变量,或将函数调用返回给变量。
例:
a, b = f()
f()返回两个值,第一个赋给a,第二个赋给b。
应该尽可能的使用局部变量,有两个好处:
1. 避免命名冲突。
2. 访问局部变量的速度比全局变量更快。
索引
对 table 的索引使用方括号 []。Lua 也提供了 . 操作。
t[i]
t.i -- 当索引为字符串类型时的一种简化写法
gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用
例如:
> site = {}
> site["key"] = "www.w3cschool.cc"
> print(site["key"])
www.w3cschool.cc
> print(site.key)
www.w3cschool.cc
变量类型:
注:可以使用Type函数测试变量的类型。
3.1 nil
nil 表示没赋值的变量,实际上可以表示删除变量。
3.2Boolean
Boolean类型的变量只有两种值 :true和false.
3.3string
3.3.1用两个方括号也可以表示一块字符串
特殊字符串:
\a 响铃 \v 垂直指标
\b 退格 \\ 反斜杠
\f 换页符 \" 双引号
\n 换行符 \' 单引号
\r 换行符 \[ 左方括号
\t 制表符 \] 右方括号
\o 空字符 \ddd 八进制
\xhh 十六进制
3.3.2在对一个数字字符串进行操作时,Lua会将这个数字字符串转换成一个数字。
例子:
print(2+6)--8
print("2"+6)--8
print("2"+"6")--8
print("2+6")--2+6
print("abc"+6)--报错,字符串连接不是用+而是两点 ..
print("2"..6)--26
注:..(连接字符串)
#(计算字符串长度,置于字符串前或者变量名前)
3.4Number
双精度浮点数,无整数类型
myNumber=7
myNumber=0.765
myNumber=7.65e8(7.65x10^8,765 000 000)
myNumber=7.65e-2(7.65x10^-2,0.0765)
3.5table
3.5.1实质是关联数组(associative arrays)索引为数字或字符串,初始索引为1.
3.5.2table的创建
3.5.2.1空表
local tab1={}
3.5.2.2初始表
local tab2={"apple","pear"}
注:table不会固定长度大小,有新数据添加时,table会自动增长,没有初始值都为nil.
3.6局部变量和全局变量
Lua变量默认是全局的,也就是说,变量的值在整个会话中是保持不变的,除非脚本改变了它。
当使用全局变量时,变量名前加一个g字母会更加明确,便于调试。
局部变量可以给设定一个初始值,也可以不用赋值。
语法:
local 变量名
变量的有效范围取决于声明变量的位置。
4.运算符
4.1算术运算符
+-*/%^-
4.2关系运算符
==
~=
>
<
>=
<=
注:如果使用关系运算符比较两个table,只有两个table是同一个对象的时候才能得到预期的结果,因为变量只是table对象的引用(像指针一样),不能直接比较存在于table中的值。
实例:
tableA={1,2,3}
tableB={1,2,3}
if tableA=tableB then
print("相等")
else
print("不相等")
end
-->不相等(结构不同)
tableA={1,2,3}
tableB=tableA
if tableA=tableB then
print("相等")
else
print("不相等")
end
-->相等(tableB指向了同样的对象tableA)
4.3逻辑运算符
and(比较两个参数时,第一个false则返回flase,否则返回第二个参数的值)
or
not
注:官方解释的是一坨屎,就和C一样理解就行。
4.4其他运算符
.. 连接字符串
#一元运算符,返回字符串或表的长度
4.5运算符的优先级
从高到低的顺序:
^
not - (unary)
* /
+ -
..
< > <= >= ~= ==
and
or
注:
除了^和..外所有的二元运算符都是左连接的。
a+i < b/2+1 <--> (a+i) < ((b/2)+1)
5+x^2*8 <--> 5+((x^2)*8)
a < y and y <= z <--> (a < y) and (y <= z)
-x^2 <--> -(x^2)
x^y^z <--> x^(y^z)
实例
我们可以通过以下实例来更加透彻的了解 Lua 语言运算符的优先级:
a = 20
b = 10
c = 15
d = 5
e = (a + b) * c / d;-- ( 30 * 15 ) / 5
print("(a + b) * c / d 运算值为 :",e )
e = ((a + b) * c) / d; -- (30 * 15 ) / 5
print("((a + b) * c) / d 运算值为 :",e )
e = (a + b) * (c / d);-- (30) * (15/5)
print("(a + b) * (c / d) 运算值为 :",e )
e = a + (b * c) / d; -- 20 + (150/5)
print("a + (b * c) / d 运算值为 :",e )
以上程序执行结果为:
(a + b) * c / d 运算值为 : 90.0
((a + b) * c) / d 运算值为 : 90.0
(a + b) * (c / d) 运算值为 : 90.0
a + (b * c) / d 运算值为 : 50.0
注:除了^和..外所有二元运算符都是左连接的。
笔记:
1.在Lua中实现C/C++中的三目运算。
condition? result1:result2
|
if condition then
return result1
else
return result2
end
三目运算
熟悉 C/C++ 的老司机都知道三目运算 a ? b : c,这种写法替换简单的条件判断语句可以在不增加阅读难度的情况下,使代码尽量保持简洁。
int a, b, ret;
//if-else
if (a > b)
ret = a;
else
ret = b;
//三目运算符
ret = a > b ? a : b;
Lua 中的三目运算
Lua 原生的语义并没有实现三目运算,一般是通过逻辑运算符 and 和 or 来模拟三目运算符的。
Lua 中 and 和 or 都使用"短路求值(short_cur evaluation)",也就是说,它们只会在需要时才去评估第二个操作数。(《Lua程序设计》)
local a, b, ret;
ret = a > b and a or b
穷举所有可能性:
a > b 时:
a > b and a –> true
a or b –> a
a <= b时:
a > b and a –> false
a or b –> b
完美!
Lua 中的三目运算符陷阱
按照从特殊到一般的原则:
三目运算的一般形式a ? b : c
a = true,结果为b
a = false,结果为c
对应Lua中的a and b or c
b = true
a = true
a and b –> true
b or c –> b
a = false
a and b –> false
b or c –> c
b = false
a = true
a and b –> false
b or c –> c
a = false
a and b –> false
b or c –> c
可以看到当 b = false 时,Lua模拟的 a and b or c 始终返回 c 并不能还原三目运算符的原貌。
《Lua程序设计》也建议这种情况使用 if-else 来避免。
一般化的 a and b or c
那么有没有办法可以解决 b = false 失效的问题呢?
由此我联想到 C 语言有一道常规的考题:请使用宏定义写一个返回两个值中较小值的方法。
在校时第一次看到本题,第一反应如下:
#define MIN(A,B) A < B ? A : B
然而这种写法在很多嵌套的使用环境中都不能返回正确的结果。比如:2 * MIN(3, 4)展开为 2 * 3 < 4 ? 3 : 4 = 6 < 4 ? 3 : 4,结果为4。
更"工程师"的写法是:
#define MIN(A,B) ((A) < (B) ? (A) : (B))
还有好奇心的同学可以参考:宏定义的正确写法,三目运算的宏定义
从这个示例中,我就在想如何能保证 a and b or c 中 b 为真或者 b 不产生歧义呢?
and的运算优先级高于or,简单的改变运算顺序并没有用。
这时就想到了lua中万能的table,能不能把a,b,c都放到table中来改变b的存在呢?要注意{nil}也是一个为true的对象。
a,b,c都替换为table:{a} and {b} or {c}。
三目运算中a是条件,结果是b或者c。其实a并不需要放入table中,否则{a}就始终为true了,失去了条件的意义。而{b} or
{c}的结果也必然是一个table,该table只有一个元素。那么通过[1]即可访问。
综上所述,更一般化的Lua三目运算为:(a and {b} or {c})[1]
2.其他运算符 —— #
在获取表的长度时,根据的是表的最大索引的值:
tab1 = {"1","2"}
print("tab1长度"..#tab1)
tab2 = {key1="1","2"}
print("tab2长度"..#tab2)
tab3 = {}
tab3[1]="1"
tab3[2]="2"
tab3[4]="4"
print("tab3长度"..#tab3)
输出:
tab1长度2
tab2长度1
tab3长度4
3. 下标越过 1 位以上,长度还是为 2:
tab3={}
tab3[1]="1"
tab3[2]="2"
tab3[5]="5"
print("tab3的长度",#tab3)
输出:
tab3的长度 2
4.取长度操作符写作一元操作 #
table t 的长度被定义成一个整数下标 n 。 它满足 t[n] 不是 nil 而 t[n+1] 为 nil; 此外,如果 t[1] 为 nil ,n 就可能是零。 对于常规的数组,里面从 1 到 n 放着一些非空的值的时候, 它的长度就精确的为 n,即最后一个值的下标。 如果数组有一个“空洞” (就是说,nil 值被夹在非空值之间), 那么 #t 可能是指向任何一个是 nil 值的前一个位置的下标 (就是说,任何一个nil 值都有可能被当成数组的结束)。
tab4 = {}
tab4[1] = "1"
tab4[2] = nil
tab4[3] = "2"
tab4[4] = nil
print("tab4的长度", #tab4)
--tab4的长度 1
tab5 = {}
tab5[1] = "1"
tab5[2] = nil
tab5[3] = "2"
tab5[4] = "4"
print("tab5的长度", #tab5)
--tab5的长度 4
tab6 = {1, nil, 3}
print("tab6的长度", #tab6)
--tab6的长度 3
tab6 = {1, nil, 3, nil}
print("tab6的长度", #tab6)
--tab6的长度 1
5.控制结构
注:
控制结构的条件表达式结果可以是任何值,Lua认为false和nil为假,true和非nil为真。
要注意的是Lua中 0 为 true:
5.1if 语句
if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。
Lua if 语句语法格式如下:
if(布尔表达式)
then
--[ 在布尔表达式为 true 时执行的语句 --]
end
在布尔表达式为 true 时会if中的代码块会被执行,在布尔表达式为 false 时,紧跟在 if 语句 end 之后的代码会被执行。
Lua认为false和nil为假,true 和非nil为真。要注意的是Lua中 0 为 true。
5.2if...else 语句
if 语句 可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码。
if...else 语句
Lua if 语句可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码块。
Lua if...else 语句语法格式如下:
if(布尔表达式)
then
--[ 布尔表达式为 true 时执行该语句块 --]
else
--[ 布尔表达式为 false 时执行该语句块 --]
end
在布尔表达式为 true 时会if中的代码块会被执行,在布尔表达式为 false 时,else 的代码块会被执行。
Lua认为false和nil为假,true 和非nil为真。要注意的是Lua中 0 为 true。
if...elseif...else 语句
Lua if 语句可以与 elseif...else 语句搭配使用, 在 if 条件表达式为 false 时执行 elseif...else 语句代码块,用于检测多个条件语句。
Lua if...elseif...else 语句语法格式如下:
if( 布尔表达式 1)
then
--[ 在布尔表达式 1 为 true 时执行该语句块 --]
elseif( 布尔表达式 2)
then
--[ 在布尔表达式 2 为 true 时执行该语句块 --]
elseif( 布尔表达式 3)
then
--[ 在布尔表达式 3 为 true 时执行该语句块 --]
else
--[ 如果以上布尔表达式都不为 true 则执行该语句块 --]
end
5.3if 嵌套语句
你可以在if 或 else if中使用一个或多个 if 或 else if 语句 。
if...else 语句
Lua if 语句允许嵌套, 这就意味着你可以在一个 if 或 else if 语句中插入其他的 if 或 else if 语句。
Lua if 嵌套语句语法格式如下:
if( 布尔表达式 1)
then
--[ 布尔表达式 1 为 true 时执行该语句块 --]
if(布尔表达式 2)
then
--[ 布尔表达式 2 为 true 时执行该语句块 --]
end
end
你可以用同样的方式嵌套 else if...else 语句。
注:Lua不支持case语句因此可以用elseif语句
5.4循环
Lua 语言提供了以下几种循环处理方式:
while 循环
在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for 循环
重复执行指定语句,重复次数可在 for 语句中控制。
repeat...until
重复执行循环,直到 指定的条件为真时为止
循环嵌套
可以在循环内嵌套一个或多个循环语句(while do ... end;for ... do ... end;repeat ... until;)
5.4.1while
注:
while和repeat 控制结构非常相似,它们都可以循环执行一段脚本直到满足某个条件。
Lua 编程语言中 while 循环语句在判断条件为 true 时会重复执行循环体语句。
语法
Lua 编程语言中 while 循环语法:
while(condition)
do
statements
end
5.4.2repeat
repeat...until 循环的条件语句在当前循环结束后判断。
语法
Lua 编程语言中 repeat...until 循环语法格式:
repeat
statements
until( condition )
5.4.3for
Lua 编程语言中 for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。
Lua 编程语言中 for语句有两大类:
数值for循环
泛型for循环
5.4.3.1数值for循环
Lua 编程语言中数值for循环语法格式:
for var=exp1,exp2,exp3 do
<执行体>
end
var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1。
示例:
for i=10,1,-1 do
print(i)
end
从10变到1,每次减1
结果:10,9,8,7,6,5,4,3,2,1
5.4.3.2泛型for循环
泛型for循环通过一个迭代器函数来遍历所有值,类似java中的foreach语句。
Lua 编程语言中泛型for循环语法格式:
--打印数组a的所有值
for i,v in ipairs(a)
do print(v)
end
i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。
days ={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
for i,v in ipairs(days) do
print(v)
end
结果略(ipairs(为表达式列表),后面泛型for里有提到)
注:
1.循环次数只是在第一次执行时确定,因此就算用户更改了参数的值也不会影响最终的循环次数。
2.循环结构中的变量是局部变量,一旦循环结束就会被清除。如果想保存它们的值
,那么必须使用全局变量或者更高级的局部变量。
笔记:
1.
在lua中pairs与ipairs两个迭代器的用法相近,但有一点是不一样的:
pairs可以遍历表中所有的key,并且除了迭代器本身以及遍历表本身还可以返回nil;
但是ipairs则不能返回nil,只能返回数字0,如果遇到nil则退出。它只能遍历到表中出现的第一个不是整数的key
2.pairs遍历表中全部key,value
ipairs从下标为1开始遍历,然后下标累加1,如果某个下标元素不存在就终止遍历。这就导致如果下标不连续或者不是从1开始的表就会中断或者遍历不到元素。
3.
首先,ipairs 这个迭代器只能遍历所有数组下标的值,这是前提,也是和 pairs 的最根本区别,也就是说如果 ipairs 在迭代过程中是会直接跳过所有手动设定key值的变量。
特别注意一点,和其他多数语言不同的地方是,迭代的下标是从1开始的。
3.1
例如:
tab = {1,2,a= nil,"d"}
for i,v in ipairs(tab) do
print(i,v)
end
输出结果为:
1 1
2 2
3 d
这里是直接跳过了a=nil这个变量
3.2
ipairs在迭代过程中如果遇到nil时会直接停止。
例如:
tab = {1,2,a= nil,nil,"d"}
for i,v in ipairs(tab) do
print(i,v)
end
输出结果为:
1 1
2 2
4.
for 循环中,循环的索引 i 为外部索引,修改循环语句中的内部索引 i,不会影响循环次数:
for i=1,10 do
i = 10
print("one time,i:"..i)
end
仍然循环 10 次,只是 i 的值被修改了。
5.5嵌套循环
语法
Lua 编程语言中 for 循环嵌套语法格式:
for init,max/min value, increment
do
for init,max/min value, increment
do
statements
end
statements
end
Lua 编程语言中 while 循环嵌套语法格式:
while(condition)
do
while(condition)
do
statements
end
statements
end
Lua 编程语言中 repeat...until 循环嵌套语法格式:
repeat
statements
repeat
statements
until( condition )
until( condition )
除了以上同类型循环嵌套外,我们还可以使用不同的循环类型来嵌套,如 for 循环体中嵌套 while 循环。
实例
以下实例使用了for循环嵌套:
j =2
for i=2,10 do
for j=2,(i/j) , 2 do
if(not(i%j))
then
break
end
if(j > (i/j))then
print("i 的值为:",i)
end
end
end
以上代码执行结果为:
i 的值为: 8
i 的值为: 9
i 的值为: 10
5.6循环控制语句
循环控制语句用于控制程序的流程, 以实现程序的各种结构方式。
Lua 支持以下循环控制语句:
break 语句
退出当前循环或语句,并开始脚本执行紧接着的语句。
5.7无限循环
在循环体中如果条件永远为 true 循环语句就会永远执行下去,以下以 while 循环为例:
while( true )
do
print("循环将永远执行下去")
end