Lua 的基础语法笔记
Lua 基础语法笔记
Lua 是一种轻量小巧的脚本语言, 使用标准C语言编写并以源代码形式开放.
其设计目的是为了嵌入应用程序中, 从而为应用程序提供灵活的扩展和定制功能.
Lua 是巴西里约热内卢天主教大学 (Pontifical Catholic University of Rio de Janeiro) 里的一个研究小组于 1993 年开发的, 该小组成员有: Roberto Ierusalimschy, Waldemar Celes, Luiz Henrique de Figueiredo
注释
单行注释
Lua 中的单行注释用 --
表示
1 | -- Hello World |
多行注释
Lua 中的多行注释由 --[[
开始, 以 --]]
结束
1 | --[[ |
关键字
Lua中一共有 22 个关键字
- and
布尔运算和 - break
跳出循环 - do
代码块开始标记 - else
分支语句表示默认分支 - elseif
分支语句表示另一个条件分支 - end
代码块结束标记 - false
条件假 - for
循环语句关键字 - function
函数声明关键字 - if
分支语句关键字 - in
迭代关键字 - local
局部变量声明关键字 - nil
空类型声明关键字 - not
布尔运算非 - or
布尔运算或 - repeat
直到循环声明关键字 - return
函数返回关键字 - then
分支语句关键字 - true
条件真 - until
直到循环声明关键字 - while
当循环声明关键字 - goto
跳转语句关键字
变量类型
Lua 中的变量分为全局变量和局部变量, 声明变量时未加 loacl
关键字的变量为全局变量
全局变量的首字母通常大写
1 | Var = nil -- 全局变量 |
数据类型
Lua 中由8种数据类型, 分别是
- nil
- boolean
- number
- string
- table
- function
- userdata
- thread
nil 类型
nil类型的变量只有一种值, 即nil, 表示空
1 | local var = nil |
boolean 类型
Lua 中所有数据类型都可视作 boolean 类型, false 和 nil 看作是 false,其他的都为 true
1 | local var = true -- boolean false 和 nil 看作是 false,其他的都为 true |
number 类型
Lua 中 的数字默认可分为 64 位整数和 64 位浮点数
1 | local var = 123 |
string 类型
Lua 中声明 string 类型变量由三种方式, 声明单行 string 可用 '
或 "
, 声明多行 string 可用 [[
开始, ]]
结束
1 | local var = 'abc' |
1 | print("2" + "6") -- output: 8 |
funcyion 类型
Lua 的函数类型变量分为有名函数和匿名函数
匿名函数通常用作给函数传参来使用
1 | local var = function() end |
1 | print(type(function() end)) -- output: function |
table 类型
Lua 中唯一的一种内置的数据结构就是表, 由许多 k, v 键值对组成
1 | local var = {} |
userdata 类型
Lua 中的 userdata 类型变量表示任意存储在变量中的C数据结构
thread 类型
Lua 中的 thread 类型变量表示执行的独立线路,用于执行协同程序
函数
Lua 中的函数是一种数据类型, 具体声明结构为
1 | function fun_name(arg1, arg2, arg3, ...) |
函数调用形式为
1 | local r1, r2, r3 = fun('arg1', 'arg2', function () end, '1') -- 函数调用 |
lua 中 . 和 : 的区别
首先在lua中使用 :
定义的函数会自动传入一个名为self的变量,这个变量是隐含的,self同c++中的this一样,表示当前对象的指针, 而 .
定义的函数中没有self
例如:
1 | Class = {} |
表
Lua 中声明表时可对表进行初始化
1 | local var = {index1 = 'index1', index2 = 2} |
填充表时可用.
运算符或[]
运算符
1 | table.index1 = 1 |
删除表中的值时直接将该元素置为 nil 即可
1 | table.index2 = nil |
访问表中元素时可用索引去取值, 或者使用^遍历的方法访问表
1 | print(table['index1']) |
数组
当声明表并对其初始化时不填写索引或之后用 [数字] 的方式填表中的充值, 那么此时这个表可视为数组
Lua 的默认索引是从 1 开始的
1 | local array = {1, 2, 3} |
可使用^遍历的方法访问数组
标签
Lua 中使用 ::tag_name::
的形式声明标签, 通常标签和 goto
关键字搭配使用
赋值语句
Lua 可以对多个变量同时赋值, 例如local a, b = 1,2
当变量个数和值的个数不一致时,Lua会以变量个数为基础采取以下策略:
- 变量个数 > 值的个数 按变量个数补足nil
- 变量个数 < 值的个数 多余的值会被忽略
分支语句
1 | if condition then |
循环语句
循环语句中可用 break
关键字跳出当前循环, 或搭配标签和 goto
关键字实现 continue
当型循环
1 | while condition do |
直到型循环
1 | :: continue::repeat |
for循环
普通 for 循环
1 | for i = 1, 5, 2 do |
遍历表
1 | for k, v in pairs(table) do |
遍历数组
1 | for i, v in ipairs(array) do |
运算符
Lua 中有以下运算符
+ 加法
- 减法
* 乘法
/ 除法
% 取余
^ 乘幂
- 负号
// 整除运算符(>=lua5.3)
== 等于
~= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
and 逻辑与
or 逻辑或
not 逻辑非
.. 连接两个字符串
# 一元运算符,返回字符串或表的长度
运算优先级由高到低排列为
优先级 | 运算符 |
---|---|
1 | ^ |
2 | not, - (unary) |
3 | *, /, % |
4 | +, - |
5 | .. |
6 | <, >, <=, >=, ~=, == |
7 | and |
8 | or |
模块
Lua 中引如其他模块使用require("module_name")
函数, 此时当前程序内会引入一个其他模块名称的表
1 | require("module") |
元表
元表用于为表定义一些行为, 为表添加元表的方法为
1 | local a_table = {} -- 普通表 |
函数名称 | 函数作用 |
---|---|
__index | 当通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键. 如果__index包含一个表,Lua会在表格中查找相应的键 |
__newindex | 当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作 |
__call | 在把普通表视作函数并调用时调用 |
__tostring | 修改表的输出行为 |
__add | 对应的运算符 ‘+’ |
__sub | 对应的运算符 ‘-‘ |
__mul | 对应的运算符 ‘*’ |
__div | 对应的运算符 ‘/‘ |
__mod | 对应的运算符 ‘%’ |
__unm | 对应的运算符 ‘-‘ |
__concat | 对应的运算符 ‘..’ |
__eq | 对应的运算符 ‘==’ |
__lt | 对应的运算符 ‘<’ |
__le | 对应的运算符 ‘<=’ |
协同程序(coroutine)
函数 | 作用 |
---|---|
coroutine.create(func) | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
coroutine.resume() | 启动 coroutine,和 create 配合使用 |
coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 查看 coroutine 的状态(coroutine 的状态有三种:dead,suspended,running) |
coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号 |
1 | local co = coroutine.create( |
1 | local wr = coroutine.wrap( |
I/O
IO模式
参数 | 作用 |
---|---|
r | 读模式 |
w | 写模式 |
a | 追加模式 |
r+ | 更新模式,所有之前的数据都保留 |
w+ | 更新模式,所有之前的数据都删除 |
a+ | 追加更新模式,所有之前的数据都保留,只允许在文件尾部做写入 |
rb | 读模式(二进制方式) |
wb | 写模式(二进制方式) |
ab | 追加模式(二进制方式) |
r+b | 更新模式,所有之前的数据都保留(二进制方式) |
w+b | 更新模式,所有之前的数据都删除(二进制方式) |
a+b | 追加更新模式,所有之前的数据都保留,只允许在文件尾部做写入(二进制方式) |
简单模式
1 | file = io.open("test.lua", "a") -- 以附加的方式打开只写文件 |
io.read()参数
参数 | 作用 |
---|---|
“*n” | 读取一个数字并返回它 |
“*a” | 从当前位置读取整个文件 |
“*l”(默认) | 读取下一行,在文件尾 (EOF) 处返回 nil |
number | 返回一个指定字符个数的字符串,或在 EOF 时返回 |
其他的 io 函数
函数 | 作用 |
---|---|
io.tmpfile() | 返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除 |
io.type(file) | 检测obj是否一个可用的文件句柄 |
io.flush() | 向文件写入缓冲中的所有数据 |
io.lines(optional file name) | 返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回 nil,但不关闭文件 |
完全模式
1 | file = io.open("test.lua", "r") -- 以只读方式打开文件 |
file:read()参数
参数 | 作用 |
---|---|
“*n” | 读取一个数字,根据 Lua 的转换文法返回浮点数或整数 |
“*a” | 从当前位置开始读取整个文件 |
“*l” | 读取一行并忽略行结束标记 (默认) |
“*L” | 读取一行并保留行结束标记 |
其他函数
函数 | 作用 |
---|---|
file:seek(optional whence, optional offset) | 设置和获取当前文件位置,成功则返回最终的文件位置(按字节),失败则返回nil加错误信息 |
file:flush() | 向文件写入缓冲中的所有数据 |
io.lines(optional file name) | 打开指定的文件 filename 为读模式并返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回 nil,并自动关闭文件. 若不带参数时io.lines() <=> io.input():lines(); 读取默认输入设备的内容,但结束时不关闭文件 |
file:seek()参数:
- whence 值可以是:
- “set”: 从文件头开始
- “cur”: 从当前位置开始[默认]
- “end”: 从文件尾开始
- offset 偏移量(默认为0)
断言
1 | assert(type(true) == "number", "true 不是一个数字") |
错误
error()
error(messahe, level) 函数可终止正在执行的函数,并返回message的内容作为错误信息(error函数永远都不会返回)
通常情况下,error会附加一些错误位置的信息到message头部
参数名称 | 意义 |
---|---|
messaage | 错误信息 |
level | 指示获得错误的位置 Level=1[默认]: 为调用error位置(文件+行号) Level=2: 指出哪个调用error的函数的函数 Level=0: 不添加错误位置信息 |
错误处理
pcall()
pcall接收一个函数和要传递给后者的参数,并执行,执行结果:有错误、无错误;返回值true或者或false, errorinfo
pcall以一种”保护模式”来调用第一个参数,因此pcall可以捕获函数执行中的任何错误
通常在错误发生时,希望落得更多的调试信息,而不只是发生错误的位置. 但pcall返回时,它已经销毁了调用桟的部分内容
1 | if pcall(function (x, y, z) error('ERROR') end, 1, 2, 3) then |
xpcall()
xpcall接收第二个参数——一个错误处理函数,当错误发生时,Lua会在调用桟展开(unwind)前调用错误处理函数,于是就可以在这个函数中使用debug库来获取关于错误的额外信息了
debug库提供了两个通用的错误处理函数:
- debug.debug(): 提供一个Lua提示符,让用户来检查错误的原因
- debug.traceback(): 根据调用桟来构建一个扩展的错误消息
1
2
3
4
5
6
7
8
9
10local myfunction = function (x, y)
x = y / nil
end
local myerrorhandler = function ( err )
print( "ERROR:", err )
end
local status = xpcall(myfunction, myerrorhandler, 1, 2)
print(status)