Lua基础
Lua是一种灵活小巧的脚本语言,可以被嵌入应用程序中,为应用程序提供灵活的扩展和定制功能。
注释
单行注释
1 |
|
多行注释
1 | --[[ |
变量
变量标识符
Lua的变量标识符用大小写字母、下划线、数字等组成,必须用字母或下划线作为开头。最好不要使用下划线加大写字母的标示符,以免与Lua的保留字冲突。在Lua的变量标识符中,字母需要区分大小写。一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION
等)被保留用于 Lua 内部全局变量,_G
表示全局作用域,后边还会提到。
变量作用域
Lua中作用域分为三种:全局作用域、局部作用域、表内作用域。声明变量时会默认使用全局作用域;声明局部变量需要显式的在变量名之前加上Local
关键字。表(table)中存储的是键值对,可以根据键名来获取对应的值。
1 | var1 = 1 -- 全局 |
全局变量可以看做在名为_G
的表中的变量。
基本数据类型
在Lua中使用变量不需要提前声明,变量的类型决定于用户赋值的类型。可以使用type()
函数判断变量的类型。
Lua中有8种基本的数据类型:
- nil
- boolean
- string
- number
- table
- function
- thread
- userdata
nil
nil
类型表示没有有效值,当访问一个没有初始化的全局变量时并不会出错,而会得到nil
。
通过将全局变量和表内的变量赋值为nil
,可以达到释放该变量的目的。
1 | -- 引用未定义变量将返回 nil ,并不会出错 |
boolean
boolean 类型只有两个可选值:true
和false
,在Lua中false
和nil
被看作是“假”,其他的都为“真”。
string
与python类似,字符串可以使用两个单引号'
或两个双引号"
包裹起来表示,也可以用多行注释来表示跨行的字符串。
1 | str = 'aspythonstring' -- 像 Python 一样不可变 |
对于[[ ... ]]
形式的字符串,可以两个方括号之间加相等数量的=
,如:
1 | str = [=[ |
使用 ..
来连接两个字符串:
1 | print("a" .. 'b') -- ab |
使用#
来获取字符串长度
1 | str = "hello" |
字符串的一些操作其他操作
1 | string.upper(argument) -- 将所有的小写字母转为大写 |
number
Lua中的number都是双精度的实数值。整数同样也用number表示。
table
Lua中的table是一种关联数组(associative array),其中存储的是键值对。也可以仅指定值而使用默认的数字索引作为键。Lua的表中默认初始索引从 1 开始。table是一种非常重要的数据类型,后边专用一节细讲。
function
表示由C或Lua编写的函数。Lua中的function是“第一类值”,可以存储在变量中,可以作为参数或返回值,后边详细介绍。
thread
表示执行的独立线路,用于执行协同程序(coroutine)。
userdata
表示任意存储在变量中的C数据结构。
控制流
Lua中的代码块以总是以end
结尾(函数的定义也用end
表示结束)。在Lua中有以下一些流程控制语句。
分支语句
使用if ... then ... else
来表示分支结构。除了nil
和false
之外,其它的值(包括数字0
和空字符串''
等)均为“真”。
逻辑的与、或、非用and
、or
、not
表示,判断相等、不等使用==
、~=
。
if
判断可以多分支和嵌套,相关语句使用方式参见下例:
1 | if a <= 0 |
某些情况下可以使用以下的方式来达到C语言中问号表达式的效果:
1 | ans = aBoolValue and 'yes' or 'no' |
循环语句
Lua中的循环有以下四种方式:
while…do循环
与C语言中相似,详见下边代码,注意在Lua中没有自增和自减运算符:
1 | while num < 50 do |
for循环
for
循环指定起止的数值及步长,循环变量可以取到起止的值,当不指定迭代步长时步长使用默认值1。
1 | sum = 0 |
泛型for循环
遍历数组,对其中的每一个元素进行循环内的操作。Lua中使用迭代器函数ipairs
来遍历访问数组,详见示例代码:
1 | days = {"Suanday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"} |
其中i
是数组索引值,v
是对应索引的数组元素值。
对于非数组形式的table,使用迭代器函数pairs
来遍历访问,详见示例代码:
1 | colors = {red = "FF0000", green = "00FF00", blue = "0000FF"} |
其中其中k
是键,v
是对应的值。
repeat…until 循环
repeat
和until
之间的语句至少会执行一次。
1 | rest = 10 |
函数
函数是对语句和表达式进行抽象的主要方法,既可以用来处理一些特殊的工作,也可以用来计算一些值。
函数定义
Lua中的函数定义方式如下:
1 | [作用域] function 函数名( 参数1, 参数2, 参数3..., 参数n) |
函数的作用域有局部与全局之分。定义局部函数使用local
关键字,定义表内的函数直接将函数指定给表内对应的键。
以下的示例代码定义了一个求两个数中最大值的函数:
1 | function (num1, num2) |
以下的示例代码使用函数递归调用来实现斐波那契数列求和:
1 | function fib(n) |
Lua中的函数是“第一类值”,函数可以保存为变量。
1 | function f(x) return x * x end |
高阶函数
1 | myprint = function(param) |
输出为
1 | 这是打印函数 - ## 10 ## |
可变参数
函数可以接受可变数量的参数,在函数参数列表中使用三点(…
),表示函数有可变的参数。Lua将函数的参数放在一个叫arg
的表中,#arg
可以计算传入参数的个数。
以下示例代码用来计算几个数的平均值:
1 | function average(...) |
多返回值
Lua中的函数可以有多个返回值,返回值之间用逗号隔开,如下示例:
1 | function func(a, b, c) |
表
表是Lua中唯一的复合类型,本质是关联数组,可用来构建不同的数据类型,如数组、字典等。table中的键(数组索引)可以使用除nil
外任意类型的值。table的大小是不固定的,你可以根据自己需要进行扩容。
构造
表的构造有以下三种形式:
1 | tab1 = {} -- 构造空表 |
对于上边的第三种方式,当键为字符串时,可以省略方括号和引号,所以下边的代码与上边的第三行等价:
1 | tab3 = { key1 = "val1", key2 = "val2", [3] = "val3"} -- 指定键和值 |
Lua中的全局变量其实是存储在一个名为_G
的table中,所以,以下的代码会输出true
。
1 | print(_G['_G'] == _G) -- 输出true |
Lua中table有以下的方法:
1 | table.concat (table [, sep [, start [, end]]]) |
数组
table中省略键时,变成使用默认数字索引的数组,索引值是从1开始的。
1 | v = {'value1', 'value2', 1.21, 'gigawatts'} |
metatable
元表(metatable)可以看做表的表,类似 JavaScript中原型(prototype)的概念。使用元表(metatable)可以改变table的行为,table的每个行为都关联了对应的元方法(metamethod)。主要涉及两个方法:
setmetatable(table,metatable)
:对指定table设置元表,如果table的元表中已存在__metatable
键,setmetatable
则会失败 。为一个表的元表增加__metatable
键可以保护和锁定该表中的元方法;getmetatable(table)
:返回table的元表。
元表能够被用于定义算术运算符和关系运算符的行为。以下是一段示例代码,为表定义了加法运算。
1 | f1 = {a = 1, b = 2} |
Lua中的值都具有元