lua教程
1.Lua 运行环境
本地环境搭建
在本地搭建 Lua 编程语言的开发运行环境,你需要在你的计算机上安装如下三个软件:(1) 文本编辑器。(2) Lua 解释器。(3)Lua 编译器。
文本编辑器
文本编辑器用来编辑你的程序代码。有如下几款常用的文本编辑器软件:Windows notepad、Brief、Epsilon、EMACS、vim/vi。
在不同的操作系统中有各自不同的编辑器,而且编辑器的版本不一样。例如,Notepad 主要用在 Windows 系统中,vim/vi 不仅可以用于 Windows 系统也可以用于 Linux 和 UNIX 操作系统。
用文本编辑器编辑的文件被称为源文件。源文件中包含程序的源代码。Lua 程序的源文件经常以 .lua 作为其后缀名。
开始编写程序之前,请确保您已经安装好一个文本编辑软件,并且曾经有过写代码,将其存入文件,生成并执行的经验。
Lua 解释器
Lua 解释器是一个能让您输入 Lua 命令并立即执行的小程序。它在执行一个 Lua 文件过程中,一旦遇到错误就立即停止执行,而不像编译器会执行完整个文件。
Lua 编译器
如果将 Lua 扩展到其它语言或者应用中时,我们需要一个软件开发工具箱以及 Lua 应用程序接口兼容的编译器。
在 Windows 系统安装 Lua
在 Windows 系统环境可以安装一个叫 SciTE 的 Lua 开发 IDE (集成开发环境)。它可以在这儿下载:http://code.google.com/p/luaforwindows。
运行下载的可执行程序就可安装 Lua 语言的 IDE 了。
在这个 IDE 上,你可以创建并生成 Lua 代码。
如果你希望在命令行模式下安装 Lua,你则需要安装 MinGW 或者 Cygwin,然后在 Windows 系统中编译安装 Lua。
在 Linux 系统安装 Lua
使用下面的命令下载并生成 Lua 程序:
$ wget http://www.lua.org/ftp/lua-5.2.3.tar.gz
$ tar zxf lua-5.2.3.tar.gz
$ cd lua-5.2.3
$ make linux test
在其它系统上安装 Lua 时,比如 aix,ansi,bsd,generic,linux,mingw,posix,solaris,你需要将 make linux test 命令中的 linux 替换为相应的系统平台名称。
假设我们已经有一个文件 helloWord.lua ,文件内容如下:
print("Hello World!")
我们先使用 cd 命令切换至 helloWord.lua 文件所在的目录,然后生成并运行该文件:
$ lua helloWorld
执行上面的命令,我们可以看到如下的输出:
hello world
在 Mac OS X 系统安装 Lua
使用下面的命令可以在 Mac OS X 系统生成并测试 Lua:
$ curl -R -O http://www.lua.org/ftp/lua-5.2.3.tar.gz
$ tar zxf lua-5.2.3.tar.gz
$ cd lua-5.2.3
$ make macosx test
如果你没有安装 Xcode 和命令行工具,那么你就不能使用 make 命令。你先需要从 mac 应用商店安装 Xcode,然后在 Xcode 首选项的下载选项中安装命令行工具组件。完成上面的步骤后,你就可以使用 make 命令了。
make macosx test 命令并不是非执行不可的。即使你没有执行这个命令,你仍可以在你的 Mac OS X 系统中使用 Lua。
假设我们已经有一个文件 helloWord.lua ,文件内容如下:
print("Hello World!")
我们先使用 cd 命令切换至 helloWord.lua 文件所在的目录,然后生成并运行该文件:
$ lua helloWorld
执行上面的命令,我们可以看到如下的输出:
hello world
Lua IDE
正如前面提到的那样,Windows 系统中 SciTE 是 Lua 创始团队提供的默认的 Lua 集成开发环境(IDE)。 此外,还有一款名叫 ZeroBrane 的 IDE。 它具有跨平台的特性,支持 Windows、Mac 与 Linux。
同时,许多 eclipse 插件使得 eclipse 能成为 Lua 的 IDE。IDE 中像代码自动补全等诸多特性使得开发变得简单了很多,因此建议你使用 IDE 开发 Lua 程序。同样,IDE 也能像 Lua 命令行版本那样提供交互式编程功能。
Lua 学起来非常简单。现在,让我们开始创建我们的第一个 Lua 程序吧!
2.第一个 Lua 程序
Lua 提供交互式编程模式。在这个模式下,你可以一条一条地输入命令,然后立即就可以得到结果。你可以在 shell 中使用 lua -i 或者 lua 命令启动。输入命令后,按下回车键,就启动了交互模式,显示如下:
$ lua -i
$ Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
quit to end; cd, dir and edit also available
你可以使用如下命令打印输出:
$> print("test")
按下回车键后,你会得到如下输出结果:
'test'
默认模式编辑
使用 Lua 文件做为解释器的参数启动解释器,然后开始执行文件直到文件结束。当脚本执行结束后,解释器就不在活跃了。
让我们写一个简单的 Lua 程序。所有的 Lua 文件都扩展名都是.lua。因此,将下面的源代码放到 test.lua 文件中。
print("test")
假如你已经设置好 Lua 程序的环境,用下面的命令运行程序:
$ lua test.lua
我们会得到如下的输出结果:
test
让我们尝试使用另外的方式运行 Lua 程序。下面是修改后的 test.lua 文件:
#!/usr/local/bin/lua
print("test")
这里,我们假设你的 Lua 解释器程序在 /usr/local/bin/lua 目录下。test.lua 文件中第一行由于以 # 开始而被解释器忽略,运行这个程序可以得到如下的结果:
$ chmod a+rx test.lua
$./test.lua
我们会得到如下的的输出结果:
test
接下来让我们看一下 Lua 程序的基本结构。这样,你可以更容易理解 Lua 编程语言的基本结构单元。
Lua 中的符号
Lua 程序是由大量的符号组成的。这些符号可以分为关键字、标识符、常量、字符串常量几类。例如,下面的 Lua 语句中包含三个符号:
io.write("Hello world, from ",_VERSION,"!\n")
这三个符号分别是:
io.write
(
"Hello world, from ",_VERSION,"!\n"
)
注释
注释就是 Lua 程序中的帮助文档,Lua 解释器会自动忽略它们。所有注释都以 --[[ 开始,并以 --]]结束。如下所示:
--[[ my first program in Lua --]]
标识符
Lua 中标识符是识别变量、函数或者其它用户自定义项的名字。标符识总是以字母或者下划线开始,其后可以是零个或多个字母、下划线或数字。
Lua 标识符中不允许出现任何标点符号,比如,@,$ 或者 %。Lua 是大小写敏感的语言,因此 Manpower 和 manpower 是 Lua 中两个不同的标识符。下面所列的是一些合法标识符的例子。
mohd zara abc move_name a_123
myname50 _temp j a23b9 retVal
关键字
下面列表中所示的是 Lua 中一小部分保留字。这些保留字不能用作常量、变量以及任何标识符的名字。
| and | break | do | else |
| elseif | end | false | for |
| function | if | in | local |
| nil | not | or | repeat |
| return | then | true | until |
| while |
Lua 中的空白符
如果 Lua 程序中某一行只包含空格或者注释,那么这样的一行被称之为空行。 Lua 解释器将完全忽略这一行。
在 Lua 中,空白是用来描述空格、制表符、换行符和注释的术语。空白符用于将语句中的一部分与其它部分区分开,使得解释器可以语句中的一个元素,比如 int,何处结束,以及另一个元素从何处开始。因此,在下面的语句中:
local age
在 local 与 age 之间至少有一个空白符(通常是空格),这个空白符使得解释器可以将 local 与 age 区分开。另一方面,在下面的语句中:
fruit = apples + oranges --get the total fruit
fruit 与 = 之间以及 = 与 apples 之间的空白符都是可以没有的。但是为了程序的可读性目的,建议你在它们之间使用空白符。
3.数据类型
Lua 是动态类型编程语言,变量没有类型,只有值才有类型。值可以存储在变量中,作为参数传递或者作为返回值。
尽管在 Lua 中没有变量数据类型,但是值是有类型的。下面的列表中列出了数据类型:
| 值类型 | 描述 |
|---|---|
| nil | 用于区分值是否有数据,nil 表示没有数据。 |
| boolean | 布尔值,有真假两个值,一般用于条件检查。 |
| number | 数值,表示实数(双精度浮点数)。 |
| string | 字符串。 |
| function | 函数,表示由 C 或者 Lua 写的方法。 |
| userdata | 表示任意 C 数据。 |
| thread | 线程,表示独立执行的线程,它被用来实现协程。 |
| table | 表,表示一般的数组,符号表,集合,记录,图,树等等,它还可以实现关联数组。它可以存储除了 nil 外的任何值。 |
type 函数
Lua 中有一个 type 函数,它可以让我们知道变量的类型。下面的代码中给出了一些例子:
print(type("What is my type")) --> string
t=10
print(type(5.8*t)) --> number
print(type(true)) --> boolean
print(type(print)) --> function
print(type(type)) --> function
print(type(nil)) --> nil
print(type(type(ABC))) --> string
在 Linux 系统中运行上面的代码可以得到如下的结果:
string
number
function
function
boolean
nil
string
默认情况下,在被初始化或赋值前,所有变量都指向 nil。 Lua 中空字符串和零在条件检查时,都被当作真。所以你在使用布尔运算的时候要特别注意。在下一章中,我们会了解到更多关于这些类型的知识。
4.变量
变量就是给一块内存区域赋予的一个名字。变量使得在程序中就可以修改或读取相应的内存区域中的内容。它可以代表各种不同类型的值,包括函数与表。
变量的名字由字母、数字与下划线组成。它必须是字母或下划线开头。由于 Lua 是字母大小写敏感的,所以大写字母与小写字母是不一样的。Lua 中有八种基本值类型: 在 Lua 语言中,虽然我们没有变量数据类型,但是依据变量的作用域我们可以将变量分为三类:
- 全局变量:除非显示的声明一个局部变量,否则所有的变量都被默认当作全局变量。
- 局部变量:如果我们将一个变量定义为局部变量,那么这么变量的作用域就被限制在函数内。
- 表字段:这种特殊的变量可以是除了 nil 以外的所有类型,包括函数。
Lua 变量定义
一个变量定义就意味着告诉解释器在什么地方创建多大的一块存储空间。一个变量定义包括一个可选的类型( type )以及该类型的一个或多个变量名的列表,如下所示:
type variable_list;
其中,type 是可以选择指定为 local 或者不指定使用默认值 global,variable_list 是包含一个或多个由逗号分隔的标识符名字。下面是合法变量定义的示例:
local i, j
local i
local a,c
local i,j 声明定义了两个变量 i 与 j;它命令解释器创建两个名称分别为 i,j 的变量,并且将其作用域限制在局部。
在声明变量的时候可以同时初始化变量(为变量赋初值)。在变量名后跟上等号和一个常量表达式就可以初始化变量。如下所示:
type variable_list = value_list;
一些例子如下:
local d , f = 5 ,10 --声明局部变量 d,f。
d , f = 5, 10; --声明全局变量 d,f。
d, f = 10 --[[声明全局变量 d,f,其中 f 的值是 nil--]]
如果只是定义没有初始化,则静态存储变量被隐式初始化为 nil。
Lua 变量声明
正如在上面例子看到的那样,为多个变量赋值就是在变量列表后跟上值列表。例子 local d,f = 5,10 中,变量列表是 d,f,值列表是 5,10。
Lua 赋值时会将第一个值赋给第一个变量,第二个值赋给第二个变量,依次类推。所以,d 的值是 5,f 的值是 10。
示例
下面的示例中,变量被声明在顶部,但是它们在主函数中定义和初始化:
– 变量定义:
local a, b
– 初始化
a = 10
b = 30
print("value of a:", a)
print("value of b:", b)
– 交换变量的值
b, a = a, b
print("value of a:", a)
print("value of b:", b)
f = 70.0/3.0
print("value of f", f)
上面的代码被编译生成和执行后,会产生如下的结果:
value of a: 10
value of b: 30
value of a: 30
value of b: 10
value of f 23.333333333333
Lua 中的左值与右值
Lua 中有两种表达式:
- 左值:引用内存位置的表达式被称之为左值表达式。左值表达式既可以出现在赋值符号的左边也可以出现在赋值符号的右边。
- 右值:术语“右值”指存在内存某个位置的数据值。我们不能为右值表达式赋值,也就是说右值表达式只可能出现在赋值符号的右边,而不可能出现在赋值符号的左边。
g = 20
但是,下面的语句是非法的,它会产生生成时错误:
10 = 20
在 Lua 语言中,除了上面讲的这种赋值,还允许在一个赋值语句中存在多个左值表达式与多个右值表达式。如下所示:
g,l = 20,30
在这个语句中,g 被赋值为 20,l 被赋值为 30。
5.Lua 数组
数组是一组有序的对象排列,既可以是一维的也可以是多维的。
在 Lua 语言中,数组是用整数索引表实现的。数组的大小并不固定,随着数组元素的增加,它可以动态地增加内存空间大小。
一维数组
一维数组可以使用一个简单的表结构表示。可以通过一个简单循环初始化数组或者读取数组中数据。示例代码如下所示:
array = {"Lua", "Tutorial"}
for i= 0, 2 do
print(array[i])
end
执行上面的代码可以得到如下的输出结果:
nil
Lua
Tutorial
从上面的例子中可以看出,当我们尝试着访问数组中一个不存在的索引时,会得到 nil 值。 Lua 语言与 C 语言不同,Lua 数组的索引是从 1 开始的,而 C 语言中索引是从 0 开始的。不过呢,你也可以在索引值为 0 或小于 0 的位置创建对象。下面的代码演示了如何使用负索引值创建并初始化数组:
array = {}
for i= -2, 2 do
array[i] = i *2
end
for i = -2,2 do
print(array[i])
end
执行上面的代码可以得到如下的输出结果:
-4
-2
0
2
4
多维数组
多维数组有以下两种实现方式:
- 数组的数组(译注:数组的每一个元素是一个数组)。
- 修改一维数组的索引值(译注:将多维数组映射到一维数组中)。
使用方法一创建 3x3 的二维数组:
– 初始化数组
array = {}
for i=1,3 do
array[i] = {}
for j=1,3 do
array[i][j] = i*j
end
end
– 访问数组元素
for i=1,3 do
for j=1,3 do
print(array[i][j])
end
end
执行上面的代码可以得到如下的输出结果:
1
2
3
2
4
6
3
6
9
通过修改数组的的索引值实现 3x3 的二维数组,示例代码如下:
– 初始化数组
array = {}
maxRows = 3
maxColumns = 3
for row=1,maxRows do
for col=1,maxColumns do
array[row*maxColumns +col] = row*col
end
end
– 访问数组元素
for row=1,maxRows do
for col=1,maxColumns do
print(array[row*maxColumns +col])
end
end
执行上面的代码可以得到如下的输出结果:
1
2
3
2
4
6
3
6
9
正如从上面例子中所看到的那样,数组中数据是基于索引存储的。这使得数组可以以稀疏的方式存储,这也是 Lua 矩阵的存储方式。正是因为 Lua 中不会存储 nil 值,所以 Lua 不需要使用任何特殊的技术就可以节约大量的空间,这一点在其它语言中是做不到的。
print("test")
6.操作符
操作符是用于告诉解释器执行特定的数学或逻辑运算的符号。Lua 语言有丰富的内置操作符,主要包括以下几类:
- 算术运算操作符
- 关系运算操作符
- 逻辑运算操作符
- 其它操作符
算术去处操作符
下面的表中列出了所有 Lua 语言支持的算术运算操作符。假设 A 变量的值为 10,B 变量的值为 20,则:
| 操作符 | 描述 | 示例 |
|---|---|---|
| + | 两个操作数据相加 | A + B = 30 |
| - | 第一个操作数减去第二个操作数据 | A - B = 10 |
| * | 两个操作数相乘 | A * B = 200 |
| % | 模除操作符 | A % B = 0 |
| ^ | 幂运算符 | A ^ 2 = 100 |
| - | 一元减操作符用于取反 | -A = -10 |
关系运算符
下面的表列出了 Lua 支持的所有关系运算符。假设 A 的值为 10,B 的值为 20,则:
| 操作符 | 描述 | 示例 |
|---|---|---|
| == | 判断两个操作数是否相等,若相等则条件为真,否则为假。 | (A == B) 为假。 |
| ~= | 判断两个操作数是否相等,若不相等则条件为真,否则为假。 | (A ~= B) 为真。 |
| > | 如果左操作数大于右操作数则条件为真,否则条件为假。 | (A > B) 为假。 |
| < | 如果左操作数小于右操作数则条件为真,否则条件为假。 | (A < B) 为真。 |
| >= | 如果左操作数大于或等于右操作数则条件为真,否则条件为假。 | (A >= B) 为假。 |
| <= | 如果左操作数小于或等于右操作数则条件为真,否则条件为假。 | (A <= B) 为真。 |
逻辑运算符
下面的表列出了 Lua 支持的所有逻辑运算符。假设 A 的值为 真(非零),B 的值为 假(零),则:
| 操作符 | 描述 | 示例 |
|---|---|---|
| and | 逻辑与运算符。如果两个操作数都非零,则条件为真。 | (A and B) 为假。 |
| or | 逻辑或运算符。如果两个操作数中其中有一个非零,则条件为真。 | (A or B) 为真。 |
| not | 逻辑非运算符。翻转操作数的逻辑状态。如果条件是真,则逻辑非运算符会将其变成假。 | !(A and B) 为真。 |
其它操作符
Lua 语言还支持另外两个操作符:
| 操作符 | 描述 | 示例 |
|---|---|---|
| .. | 连接两个字符串。 | 若 a 为 "Hello",b 为 "World",则 a..b 返回 "Hello World"。 |
| # | 一元运算符,返回字符串或者表的长度。 | #"Hello" 返回 5。 |
操作符优先级
操作符的优先级将决定表达式中的项如何组合。这会影响到表达式的求值。一些操作符比另外一些操作符有更高的优先级。例如,乘法操作符优先级比加法操作符更高。
例如 x = 7 +3*2,这里 x 的值为 13,而不是 20。这是因为操作符 * 优级级比操作符 + 优先级更高,所以先得到 3*2 的乘积,然后再加上 7。
下面的表中,从上到下优先级递减。在每个表达式中,高优先级操作数先运算。
| 分类 | 操作数 | 结合性 |
|---|---|---|
| 一元运算符类 | not # - | 从右至左 |
| 连接运算符 | .. | 从右至左 |
| 乘除运算符类 | * / % | 从左至右 |
| 加减运算符类 | + - | 从左至右 |
| 关系运算符类 | < > <= >= == ~= | 从左至右 |
| 等于运算符类 | == ~= | 从左至右 |
| 逻辑与运算符 | and | 从左至右 |
| 逻辑或运算符 | or | 从左至右 |
7.if语句
IF语句包括一个布尔表达式和一个或多个语句。
语法
Lua语言if语句的语法如下:
if(boolean_expression)
then
--[如果布尔表达式为真,statement(s) 执行。--]
end
如果布尔表达式计算结果为真,则 if 语句内的代码块执行;如果布尔表达式计算结果为假,跳过 if 语句中的代码直接执行 if 语句后面的代码。
Lua 语言中所有布尔真与非 nil 的组合的结果被当作真,而布尔假与 nil 组合被当作假。值得注意的是,Lua 中零被当作真,这一点与其它大部分语言不一样:
流程图

示例
a = 10;
if( a < 20 )
then
print("a is less than 20" );
end
print("value of a is :", a);
```
执行上面的代码可以得到如下的结果:
```lua
a is less than 20
value of a is : 10
8.嵌套if语句
在 Lua 语言中,你可以合法的嵌套使用 if-else 语句。这也就是说,你可以在一个 if 或 if-else 语句内再使用一个 if 或 if-else 语句。
语法
嵌套 if 语句的语法规则如下:
if( boolean_expression 1)
then
--[ 如果布尔表达式 1 为真,则执行此处代码。 --]
if(boolean_expression 2)
then
--[ 如果布尔表达式 2 为真(注:布尔表达式 1 为真),则执行此处代码)。 --]
end
end
你也可以像嵌套使用 if 语句那样使用嵌套使用 else if…else 语句。
示例
--[ 定义局部变量 --]
a = 100;
b = 200;
--[ 检查条件真假 --]
if( a == 100 )
then
--[ 如果前面的条件为真,再检查下面的条件。 --]
if( b == 200 )
then
--[ 如果条件为真,则输出如下内容 --]
print("Value of a is 100 and b is 200" );
end
end
print("Exact value of a is :", a );
print("Exact value of b is :", b );
执行上面的代码,可以得到如下的输出结果:
Value of a is 100 and b is 200
Exact value of a is : 100
Exact value of b is : 200


