lua快速入门 —— 基本语法
本文最后更新于:2020年2月29日 下午
概览:Lua的语法规则、变量类型。
参照书籍:《Lua程序设计(第二版)》
Lua版本:Lua 5.3.5
lua的语法规则
关键字
1 |
|
标识符
以字母或者下划线开头的字母、下划线、数字序列。(与C语言相同)
最好不要使用下划线加大写字母的标识符(可能会与lua的保留字冲突)
lua是大小写敏感的!
变量
lua的变量不需要声明。
给一个变量赋值后就会创建这个变量
当访问一个没有初始化的全局变量时也不会出错,得到值为 nil
1 |
|
需要注意的是:lua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里。变量前加local关键字的是局部变量。
注释
1 |
|
变量类型
Lua是动态类型的语言,变量不需要类型定义。
Lua中共有8种基本类型:nil、boolean、number、string、userdata、function、thread、table.
使用函数type()可以查看变量的类型
1 |
|
变量类型
nil(空)
Lua中特殊的类型,他只有一个值:nil;
一个全局变量没有被赋值以前默认值为nil;
给全局变量赋值nil可以删除该变量。
boolean(布尔)
两个取值false和true。
但要注意Lua中所有的值都可以作为条件。
在控制结构的条件中除了false和nil为假,其他值都为真。
所以Lua认为0和空串都是真。
number (双精度浮点数)
Lua中没有整数,数字只有这一种类型
数字常量的例子:
1 |
|
string (字符串)
lua中字符串可以包含任何字符。(lua是8位字节)
Lua中字符串不允许被修改。
Lua的string是由Lua自动进行内存分配和释放。一个string可以只包含一个字母也可以包含一本书,Lua可以高效的处理长字符串,1M的string在Lua中是很常见的。
字符串可用单引号或者双引号括起来表示字符串
Lua支持转义字符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23\a bell
\b back space -- 后退
\f form feed -- 换页
\n newline -- 换行
\r carriage return -- 回车
\t horizontal tab -- 制表
\v vertical tab
\\ backslash -- "\"
\" double quote -- 双引号
\' single quote -- 单引号
\[ left square bracket -- 左中括号
\] right square bracket -- 右中括号string支持通过数值来指定字符串中的字符
如:“alo” 可以用”\97lo“表示
string使用[[…]]表示字符串。这种形式的字符串可以包含多行也,可以嵌套且不会解释转义序列,如果第一个字符是换行符会被自动忽略掉。这种形式的字符串用来包含一段代码是非常方便的。
1
2
3
4
5
6
7
8
9
10
11
12
13page = [[
<HTML>
<HEAD>
<TITLE>An HTML Page</TITLE>
</HEAD>
<BODY>
Lua
[[a text between double brackets]]
</BODY>
</HTML>
]]
io.write(page)Lua会自动在string和numbers之间自动进行类型转换,当一个字符串使用算术操作符时,string就会被转成数字。
1
2
3
4print("10" + 1) --> 11
print("10 + 1") --> 10 + 1
print("-5.3e - 10" * "2") --> -1.06e-09
print("hello" + 1) -- ERROR (cannot convert "hello")反过来,当Lua期望一个string而碰到数字时,会将数字转成string。
1
2print(10 .. 20) --> 1020
print(type(10 .. 20)) --> string..在Lua中是字符串连接符,当在一个数字后面写时,必须加上空格以防止被解释错。
管字符串和数字可以自动转换,但两者是不同的,像10 == “10”这样的比较永远都是错的。如果需要显式将string转成数字可以使用函数tonumber(),如果string不是正确的数字该函数将返回nil。
1
2
3
4
5
6
7line = io.read() -- read a line
n = tonumber(line) -- try to convert it to a number
if n == nil then
error(line .. " is not a valid number")
else
print(n*2)
end反之,tostring()将数字转成字符串,这种转换一直有效
1
2print(tostring(10) == "10") --> true
print(10 .. "" == "10") --> trueLua5.1中,字符串前放置操作符”#“来获得该字符串的长度
1
2
3a = "hello"
print(#a) -->5
print(#"good\0bye") -->8
table (表)
table是Lua的主要的数据结构,具有强大的功能。
table无固定的大小,可以动态增长
就Lua的习惯而言,如果以数字作为table的索引值的话,一般从1开始
table实现了“关联数组”:可以通过整数或者任意其他类型的值(除了nil)来索引
Lua中无法声明table。创建table是通过构造表达式进行创建的。
最常用的是{}
1
2
3
4
5
6
7
8
9
10
11a = {} -- 创建一个table,并将它的引用存储到a上
k = "x"
a[k] = 10
a[20] = "great"
print(a["x"]) -->10
y = 20
print(a[y]) --> great
a["x"] = a["x"]+1
print(a["x"]) -->11table永远是“匿名的”,一个持有table的变量与table自身没有任何固定的关联
当一个程序再也没有对一个table的引用时吗,Lua的垃圾收集器(GC – garbage collection)最终会删除该table,并且复用它的内存
1
2
3
4
5
6
7
8
9
10
11
12a = {} -- 创建一个table,并将它的引用存储到a上
k = "x"
a[k] = 10
print(a["x"]) -->10
b = a
print(b["x"]) -->10
a = nil -- 删除该变量
print(b["x"]) -->10
b = nil --删除完本程序对table的引用table索引的语法糖
1
2
3
4
5
6
7a = {}
x = "y"
a[x] = 10
print(a[x]) --> 10
print(a.x) --> nil -->以字符串x为索引 表示 a["x"]
print(a.y) --> 10 -->以字符串y为索引 表示 a["y"]Lua 5.1中长度操作符 # 与table的一些用法
Lua 5.1中“#”长度操作符可以返回一个数组或者线性表的最后一个索引值(或为其大小)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20a = {}
for i=1,5 do
a[i] = io.read() -->读取一行
end
-- 打印所有读取的内容
for i=1,#a do
print(a[i])
end
---
print(a[#a]) --打印列表a的最后一个值
a[#a] = nil --删除最后一个值
a[#a+1] = 11 --将一个新的值添加到a的末尾
-- 读取一个文件的前十行
a = {}
for i=1,10 do
a[#a+1] = io.read()
endLua将nil作为界定数组结尾的标志
当一个数组中间有nil时,使用#a得到的就不会是你的预期
可以使用
table.maxn(a)
函数 – (Lua5.1新函数),来取得table的最大索引数
function (函数)
Lua中的函数可以存储在变量之中,
可以通过参数传递给其他函数,
也可以作为其他函数的返回值。
userdata (自定义类型)
userdata可将任意的C语言数据存储到Lua变量之中。
userdata用于表示一种由应用程序或C语言库所创建的新类型,例如标准的I/O库就用userdata来表示文件.
thread (线程)
表达式
算数运算符
加 + 减 - 乘 * 除 / 指数 ^ 取模 % 负号 -
和C语言的几乎相同,不过Lua中的数据都是双精度浮点数
- Lua中没有 +=, ++ ,–这一类的运算符
但是对于这些实数而言有些其他的不同
- x %1 得到x的小数部分
- x - x%1 得到x的整数部分
- x - x%0.01 精确到小数点后两位的结果
1 |
|
关系操作符
1 |
|
运算结果都是true或者false
nil只与其自身相等
对于table,userdata和function,Lua是做引用比较的,即只有他们引用同一个对象是才相等
比较字符串是按照字母次序进行比较的,与字符串长度无关
Lua遇到字符串和数字做比较会引发错误
1
2
3print(5 < 10) -->true
print("a" < "b") -->true
print("ab" < "b") -->true逻辑操作符
and or not
and和or的运算结果不是true和false,而是和它的两个操作数相关。
1
2
3a and b -- 如果a为false,则返回a,否则返回b
a or b -- 如果a为true,则返回a,否则返回b注意and和or都是短路求值,只有在需要的时候才会去评估它的第二个操作数
1
2
3
4
5
6-- 一个很实用的技巧:如果x为false或者nil则给x赋初始值v
x = x or v
-- 等价于
if not x then
x = v
endc语言的三目运算符 a ? b : c
1
2(a and b) or c
构造器是创建和初始化表的表达式。表是Lua特有的功能强大的东西。最简单的构造函数是{},用来创建一个空表。可以直接初始化数组:
1 |
|
Lua将”Sunday”初始化days[1](第一个元素索引为1),用”Monday”初始化days[2]
构造函数可以使用任何表达式初始化:
1 |
|
如果想初始化一个表作为record使用可以这样:
1 |
|
不管用何种方式创建table,我们都可以向表中添加或者删除任何类型的域,构造函数仅仅影响表的初始化。
1 |
|
每次调用构造函数,Lua都会创建一个新的table,可以使用table构造一个list:
1 |
|
这段代码从标准输入读进每行,然后反序形成链表。下面的代码打印链表的内容:
1 |
|
在同一个构造函数中可以混合列表风格和record风格进行初始化,如:
1 |
|
这个例子也表明我们可以嵌套构造函数来表示复杂的数据结构.
1 |
|
上面两种构造函数的初始化方式还有限制,比如你不能使用负索引初始化一个表中元素,字符串索引也不能被恰当的表示。下面介绍一种更一般的初始化方式,我们用[expression]显示的表示将被初始化的索引:
1 |
|
list风格初始化和record风格初始化是这种一般初始化的特例:
1 |
|
如果真的想要数组下标从0开始:
1 |
|
注意:不推荐数组下标从0开始,否则很多标准库不能使用。
在构造函数的最后的”,”是可选的,可以方便以后的扩展。
1 |
|
在构造函数中域分隔符逗号(”,”)可以用分号(”;”)替代,通常我们使用分号用来分割不同类型的表元素。
1 |
|
语句
赋值
大体和C语言类似,不过没有+=,-=
这一类的赋值。
Lua允许多重赋值,即对多个变量同时赋值。变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。
1 |
|
遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值
1 |
|
局部变量
使用local
创建一个局部变量,与全局变量不同,局部变量只在被声明的那个代码块内有效。
需要注意的是:lua中的变量如果没有特殊说明,全是全局变量,那怕是语句块或是函数里。变量前加local关键字的是局部变量。
尽可能的去使用局部变量。
- 访问局部变量比访问全局变量要快
- 局部变量会随着其作用域的消失而结束,便于垃圾收集器释放其值。
if then else语句
控制结构的条件表达式结果可以是任何值,Lua认为false和nil为假,其他值为真。
- Lua不支持switch语句。
1 |
|
while语句
1 |
|
repeat until语句
1 |
|
for 语句 数字型
1 |
|
for将用作为从exp1(初始值)到exp2(终止值),按照步长exp3执行。其中步长可以省略,默认为1.
- 三个表达式只会被计算一次,并且是在循环开始前。
- 控制变量var是局部变量自动被声明,并且只在循环内有效.
- 循环过程中不要改变控制变量的值,那样做的结果是不可预知的。如果要退出循环,使用break语句。
for 语句 范型
1 |
|
Lua的基础库提供了ipairs
,这是一个用于遍历数组的迭代器函数。在每次循环中,i会被赋予一个索引值,同时v被赋予一个对应于索引值的数组元素值。
- 控制变量是局部变量
- 不要修改控制变量的值
break 语句
break语句用来退出当前循环(for、repeat、while)
,在循环外部不可以使用。它只会跳出内部循环。
return 语句
return用来从函数返回结果,或者结束一个函数的执行。当一个函数自然结束时,结尾会有一个默认的return。
Lua语法要求break和return只能出现在block的结尾一句(也就是说:作为chunk的最后一句,或者在end之前,或者else前,或者until前),例如:
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!