Lua
1. 数据类型
1.1 nil数据类型
nil类型表示一种没有任何有效值的数据类型, 只有值为nil
1.2 boolean
boolean是布尔类型,只有两个取值:true,false。lua把false和nil看作是假,其他看作真。
1.3 number类型
lua默认只有一种number类型---------double(双精度浮点数)
1.4 String类型
string类型可由双引号或者两个中括号来表示
1.5 table类型
table是由构造表达式来表示,用{}来构建。
1.6 function类型
在lua里面,function类型是第一类值,可以存在变量里面
1.7 thread
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
1.8 userdata(自定义类型)
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。
2.变量
2.1变量基本定义
变量在使用前,必须在代码中进行声明,即创建该变量。
编译程序执行代码之前编译器需要知道如何给语句变量开辟存储区,用于存储变量的值。
Lua 变量有三种类型:全局变量、局部变量、表中的域。
Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量。
局部变量的作用域为从声明位置开始到所在语句块结束。
变量的默认值均为 nil。
2.2 赋值语句
赋值是改变一个变量值的基本方法,Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。 遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:
x, y = y, x -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i] -- swap 'a[i]' for 'a[j]'
当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略:
a. 变量个数 > 值的个数 按变量个数补足nil
b. 变量个数 < 值的个数 多余的值会被忽略
3.循环结构
- 很多情况下我们需要做一些有规律性的重复操作,因此在程序中就需要重复执行某些语句。
- 一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件。
- 循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体。
- 循环语句是由循环体及循环的终止条件两部分组成的。
- 常见的有while…do…end, for …do…end,repeat…until,
3.1 while循环结构
Lua 编程语言中 while 循环语法:
while(condition)
do
statements
end
3.2 for循环结构
for var=exp1,exp2,exp3 do
<执行体>
end
var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 “执行体”。exp3 是可选的,如果不指定,默认为1。
3.3 repeat…until循环结构
Lua 编程语言中 repeat…until 循环语法格式:
repeat
statements
until( condition )
我们注意到循环条件判断语句(condition)在循环体末尾部分,所以在条件进行判断前循环体都会执行一次。如果条件判断语句(condition)为 false,循环会重新开始执行,直到条件判断语句(condition)为 true 才会停止执行。
repeat…until 循环流程图如下:
4.流程控制
Lua 编程语言流程控制语句通过程序设定一个或多个条件语句来设定。在条件为 true 时执行指定程序代码,在条件为 false 时执行其他指定代码。
以下是典型的流程控制流程图:
lua里面控制流程有三种,if结构,if…else结构,if 嵌套语句
4.1 if结构
if(布尔表达式)
then
statement
end
4.2 if…else结构
if(布尔表达式)
then
--[ 布尔表达式为 true 时执行该语句块 --]
else
--[ 布尔表达式为 false 时执行该语句块 --]
end
4.3 if 嵌套语句
if( 布尔表达式 1)
then
--[ 布尔表达式 1 为 true 时执行该语句块 --]
if(布尔表达式 2)
then
--[ 布尔表达式 2 为 true 时执行该语句块 --]
end
end
5.函数
在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。
Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。
Lua 函数主要有两种用途:
1.完成指定的任务,这种情况下函数作为调用语句使用;
2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。
5.1 函数定义
Lua 编程语言函数定义格式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
end
解析:
- optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
- function_name: 指定函数名称。
- argument1, argument2, argument3…, argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
- function_body: 函数体,函数中需要执行的代码语句块。
- result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
5.2可变参数
Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 … 表示函数有可变的参数
我们也可以通过 select("#",…) 来获取可变参数的数量:
有时候我们可能需要几个固定参数加上可变参数,固定参数必须放在变长参数之前:
通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select(’#’, …) 或者 select(n, …)
select('#', …) 返回可变参数的长度
select(n, …) 用于访问 n 到 select('#',…) 的参数
6.运算符
运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 其他运算符
6.1算术运算符
下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为20,B 的值为 10:
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A+B=30 |
- | 减法 | A-B=10 |
* | 乘法 | A*B=200 |
/ | 除法 | A/B=2 |
% | 取余 | A%B=0 |
^ | 乘幂 | A^2=400 |
- | 负号 | -A=-20 |
6.2关系运算符
下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为10,B 的值为 20:
运算符 | 描述 | 案例 |
---|---|---|
== | 等于,检测两个值是否相等,相等返回 true,否则返回 false | (A==B)为false |
~= | 不等于,检测两个值是否相等,相等返回 false,否则返回 true | (A~=B)为true |
> | 大于,如果左边的值大于右边的值,返回 true,否则返回 false | (A>B)为false |
< | 小于,如果左边的值大于右边的值,返回 false,否则返回 true | (A<B)为true |
>= | 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false | (A>=B)为false |
<= | 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false | (A <= B) 返回 true |
6.3逻辑运算符
下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:
运算符 | 描述 | 案例 |
---|---|---|
and | 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B | (A and B)为false |
or | 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B | (A or B)为true |
not | 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false | (not A)为false |
运算符优先级
从高到低的顺序:
^ | |||||
---|---|---|---|---|---|
not | - | ||||
* | / | ||||
+ | - | ||||
… | |||||
> | < | >= | <= | == | ~= |
and | |||||
or |
除了^和…外所有的二元运算符都是左连接的。
7.字符串
字符串或串(String)是由数字、字母、下划线组成的一串字符。
Lua 语言中字符串可以使用以下三种方式来表示:
- 单引号间的一串字符。
- 双引号间的一串字符。
- [[和]]间的一串字符。
7.1 字符串操作
Lua 提供了很多的方法来支持字符串的操作:
序号 | 方法和用途 |
---|---|
1 | string.upper(argument):字符串全部转为大写字母 |
2 | string.lower(argument):字符串全部转为小写字母 |
3 | string.gsub(mainString,findString,replaceString,num):在字符串中替换,mainString为要替换的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换),如: |
4 | string.find (str, substr, [init, [end]]):在一个指定的目标字符串中搜索指定的内容(第三个参数为索引),返回其具体位置。不存在则返回 nil。 |
5 | string.reverse(arg):字符串反转 |
6 | string.format(…):返回一个类似printf的格式化字符串 |
7 | string.char(arg) 和 string.byte(arg[,int]):char 将整型数字转成字符并连接, byte 转换字符为整数值(可以指定某个字符,默认第一个字符)。 |
8 | string.len(arg) :计算字符串长度 |
9 | string.rep(string, n):返回字符串string的n个拷贝 |
10 | … 链接两个字符串 |
11 | string.gmatch(str, pattern):回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。 |
12 | string.match(str, pattern, init):string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。 在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。 |
8.数组
数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。
Lua 数组的索引键值可以使用整数表示,数组的大小不是固定的。
注意: 此处数组的下标不同于其他语言,默认不是从0开始,而是以1开始。不过也可以指定从0开始。
8.1一维数组
一维数组是最简单的数组,其逻辑结构是线性表。一维数组可以用for循环出数组中的元素,如下实例:
8.2 多维数组
多维数组即数组中包含数组或一维数组的索引键对应一个数组。
9.Lua 迭代器
迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址
在Lua中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。
9.1 泛型 for 迭代器
10.Lua table(表)
table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典等。
Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
Lua table 是不固定大小的,你可以根据自己需要进行扩容。
Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。
13.协同程序
什么是协同(coroutine)?
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
协同是非常强大的功能,但是用起来也很复杂。
线程和协同程序区别
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
基本语法
方法 | 描述 |
---|---|
coroutine.create() | 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用 |
coroutine.resume() | 重启coroutine,和create配合使用 |
coroutine.yield() | 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果 |
coroutine.status | 查看coroutine的状态 .注:coroutine的状态有三种:dead,suspend,running,具体什么时候有这样的状态请参考下面的程序 |
coroutine.wrap() | 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复 |
coroutine.running() | 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号 |
![]() |
14.文件I/O
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。
打开文件操作语句如下:
file = io.open (filename [, mode])
mode 的值有:
模式 | 描述 |
---|---|
r | 以只读方式打开文件,该文件 必须存在 |
w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立文件。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
r+ | 以可读写方式打开文件,该文件必须存在。 |
w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
a+ | 与a类似,但此文件可读可写 |
b | 二进制模式,如果文件是二进制文件,可以加上b |
+ | 表示对文件可读可写 |
简单模式
在以上实例中我们使用了io.x方法,其中io.read()中,我们并没有带参数,参数可以是下表中的一个:
模式 | 描述 |
---|---|
“*n” | 读取一个数字并返回他,例如:file.read("*n") |
“*a” | 从当前位置读取整个文件,例如:file.read("*a") |
“*I”(默认) | 读取下一行,在文件尾(EOF)处返回nil.例如:file.read("*I") |
number | 返回一个指定字符个数的字符串,或在EOF时返回nil,例如:file.read(5) |
其他的 io 方法有:
**io.tmpfile()?*返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除
io.type(file): 检测obj是否一个可用的文件句柄
io.flush(): 向文件写入缓冲中的所有数据
io.lines(optional file name): 返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,但不关闭文件
安全模式
通常我们需要在同一时间处理多个文件。我们需要使用 file:function_name 来代替 io.function_name 方法。以下实例演示了如何加粗样式同时处理同一个文件:
file:seek(optional whence, optional offset): 设置和获取当前文件位置,成功则返回最终的文件位置(按字节),失败则返回nil加错误信息。参数 whence 值可以是:
“set”: 从文件头开始
“cur”: 从当前位置开始[默认]
“end”: 从文件尾开始
offset:默认为0
不带参数file:seek()则返回当前位置,file:seek(“set”)则定位到文件头,file:seek(“end”)则定位到文件尾并返回文件大小
file:flush(): 向文件写入缓冲中的所有数据
io.lines(optional file name): 打开指定的文件filename为读模式并返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,并自动关闭文件。
若不带参数时io.lines() <=> io.input():lines(); 读取默认输入设备的内容,但结束时不关闭文件,如
for line in io.line("file.txt") do
print(line);
end
15.Lua面向对象
面向对象编程(Object Oriented Programming,OOP)是一种非常流行的计算机编程架构。
以下几种编程语言都支持面向对象编程:
- C++
- Java
- Objective-C
- Smalltalk
- C#
- Ruby
面向对象特征
1) 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
2) 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
3) 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
4)抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。
Lua 中面向对象
我们知道,对象由属性和方法组成。LUA中最基本的结构是table,所以需要用table来描述对象的属性。
lua中的function可以用来表示方法。那么LUA中的类可以通过table + function模拟出来。
至于继承,可以通过metetable模拟出来(不推荐用,只模拟最基本的对象大部分时间够用了)。
Lua中的表不仅在某种意义上是一种对象。像对象一样,表也有状态(成员变量);也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。对象有他们的成员函数,表也有: