学习资料地址:http://www.runoob.com/lua/lua-tutorial.html

安装环境

  在Windows环境下,使用SciTE来运行Lua程序。

  项目GitHub地址:https://github.com/rjpcomputing/luaforwindows/releases

  上面的官方下载无法保证下载速度,我使用的是菜鸟教程分流的下载地址:http://static.runoob.com/download/LuaForWindows_v5.1.4-46.exe

开始编程

  和Python一样,Lua也有交互式的编程方式。在命令行中输入lua或者lua -i启用。

  同时也可以使用脚本式编程,就是将代码存放在一个lua文件中,命令行执行lua xxx.lua即可。

  需要注意的是,交互式编程状态下不能使用lua命令,会出现下面的错误,这一点我也是犯了好多次:

1
stdin:1: '=' expected near 'hello'

  教程中没有提到怎样退出lua环境 。os.exit()退出。

基础知识

注释

  单行注释:

1

  多行注释:

1
2
3
4
--[[
XXX
XXX
]]

输入输出

1
print("hello world!")

数据类型与变量

变量

概述

  Lua有三种变量类型:全局变量,局部变量和表中的域。默认情况下,变量都是全局变量,函数里面没有做特殊声明的变量也都是全局变量。全局变量不需要声明,直接赋值即创建了这个全局变量。如果访问了一个没有创建的变量,会返回一个nil。同样,如果想要删除一个变量,直接赋值nil即可。

1
2
3
4
5
> print(b)
nil
> b=10
> print(b)
10

  如果想要一个局部变量,需要使用local显式声明:

1
local b = 5

赋值语句

  赋值时改变一个变量的值和改变表域的最基本方法。同大多数编程语言类似,Lua使用从右到左的赋值方式。除此之外,还能够实现多个变量同时赋值:

1
a, b = 10, 2*x

  上面的语句在功能上,等同于:

1
2
a = 10
b = 2*x

  在对多个变量进行赋值时,Lua采用的计算方式是先计算右侧的值,再进行赋值的操作。所以再Lua中,实现两个变量值的交换只需要一行代码:

1
x, y = y, x

  除此之外,当变量的个数和数值的个数不一致时,Lua会遵循这个策略:

  1. 当 变量个数 > 值的个数 时,右侧没有指定值的变量赋值为nil
  2. 当 变量个数 < 值的个数 时,右侧多余的值会被忽略掉。

  所以比较容易出现的错误是,在对多个变量进行相同赋值时:

1
2
3
4
a, b, c = 0
print(a,b,c) --> 0 nil nil
a, b, c = 0, 0, 0
print(a,b,c) --> 0 0 0

  多赋值语句,除了用在上面的值交换的过程中之外,还常用于记录函数的多个返回值。Lua中,函数可以有多个返回值。如果想要将函数f()的两个返回值存放到全局变量ab中去,可以使用下面的语句:

1
a, b = f()

  上面的语句,实现了将函数的第一个返回值给a,第二个给b。

  虽然Lua定义全局变量比较方便,但是应当尽可能地使用局部变量。因为局部变量的访问时间要比全局变量更快,同时也避免了变量命名的冲突。

数据类型

概述

  以下是常见的集中变量类型。

数据类型 描述
nil 无效值,没有赋值的变量都会返回nil
boolean 布尔
number 双精度浮点型
string 字符串,用单引号或双引号括起来
function 由C或Lua编写的函数
userdata *表示任意存储在变量中的C数据结构
thread *表示执行的独立线路,用于执行协同程序
table *Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。

  可以使用type函数测试给定变量或常量的类型:

1
2
3
4
5
6
7
print(type("Hello world")) --> string
print(type(10.4*3)) --> number
print(type(print)) --> function
print(type(type)) --> function
print(type(true)) --> boolean
print(type(nil)) --> nil
print(type(type(X))) --> string

nil(空)

  nil类型表示没有任何有效值,只有一个值,nil。打印一个没有赋值的变量会输出nil。对于全局变量和table变量,nil可以起到删除的作用。全局变量或者 table表里的变量赋一个nil值,等同于将他们删除。

  nil在比较时,需要使用双引号括起来。

1
2
3
4
5
6
7
> type(X)
nil
> type(X)==nil
false
> type(X)=="nil"
true
>

boolean(布尔)

  Lua的布尔值与其他语言有一个显著的区别,它将false和nil看作假,其他的值,包括0,都为真。长时间使用其他编程语言的人可能会很难反应过来。

  除此之外,在进行逻辑判断时也和其他语言有很多不同。进行或、与运算时,如0 or false的值就为0,10 and 20返回值就为20。

number(数字)

  Lua默认只有一种number类型,即双精度浮点型。

string(字符串)

  字符串由一对单引号或者双引号括起来。

1
string1 = "this is string1"

  也可以使用两个方括号[[]]来表示一块字符串。

1
2
3
4
5
6
7
8
html = [[
<html>
<head></head>
<body>
<a href="http://www.z16388.com/">崎径 其镜</a>
</body>
</html>
]]

  运行时,Lua会自动在string和number之间进行格式转换。

1
2
3
4
print("10"+ 1) --> 11
print("10 + 1") --> 10 + 1
print("hello"+ 1) -- 报错 (无法转换 "hello")
print(10 .. 20) --> 1020

  在一个数字后写..时应该加空格,防止被错误解释

  可以使用两点..来连接两个字符串:

1
2
3
4
> print("a" .. 'b')
ab
> print(157 .. 428)
157428

  可以使用#来计算字符串的长度:

1
2
3
4
5
> len = "www.z16388.top"
> print(#len)
14
> print(#"www.z16388.top")
14

table(表)

  表是一个关联数组,可以创建空表,也可以在创建的时候初始化:

1
2
local tbl1 = {}
local tbl2 = {"apple", "pear", "orange", "grape"}

  数组的索引可以是数字或者字符串:

1
2
a[key] = 22
a[2] = 11

  需要注意的是,与其他语言不同,Lua默认初始索引是从1开始的!!!!

1
2
3
4
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
print("Key", key)
end

  程序的运行结果是:

1
2
3
4
Key 1
Key 2
Key 3
Key 4

  对table的索引除了使用国际惯例[]之外,还可以使用.进行操作。需要注意的是,使用点号来索引时,索引的关键字不能为数字

1
2
3
4
5
6
> site = {}
> site["key"] = "www.z16388.top"
> print(site["key"])
www.z16388.top
> print(site.key)
www.z16388.top

  最后,table不会固定长度,没有被赋值的部分,返回值都为nil。如果直接使用for循环进行遍历,循环会在遇到nil值时终止,可能无法实现对整个数组的遍历。(如果其中有空值的话)具体的解决方法在table部分给出。

function(函数)

  在Lua中,函数被看作第一类值,函数可以存在变量里。

1
2
3
4
5
6
7
8
9
10
function (n)
if n == 0 then
return 1
else
return n * factorial1(n - 1)
end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))

  可以以匿名函数的方式,通过参数传递。函数之所以有名字,就是为了方便进行调用。而只使用一次的函数,则可以不起名字,也就是匿名函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
function testFun(tab,fun)
for k ,v in pairs(tab) do
print(fun(k,v));
end
end
tab={key1="val1",key2="val2"}
testFun(tab,
function(key,val)--匿名函数
return key.."="..val
end
);

循环与流程控制

循环语句

while循环

  条件为true时会重复执行循环体的语句。

1
2
3
4
while(condition)
do
statements
end

for循环

  for循环是可以制定循环体执行次数的循环语句。Lua中的for循环需要相当地注意,分为两大类:

数值for循环

1
2
3
for var=exp1,exp2,exp3 do
<执行体>
end

  exp1为初值,exp2为终值,exp3为步长。若exp3不指定,值默认为1。需要注意的是,表达式中三个参数的值都会在循环开始前一次性求值,以后不再进行求值

  参数

泛型for循环

  泛型for循环,通过一个迭代器来遍历所有的值,与C++类似。

1
2
3
for i,v in ipairs(a)
do print(v)
end

  其中,i是索引,v是索引对应的元素的值,ipairs是Lua提供的一个迭代器函数,用来迭代数组。它的参数a就是数组名。下面是一个对数组进行泛型for循环输出的例子。

1
2
3
4
days = {"Suanday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
for i,v in ipairs(days) do
print(v)
end

repeat … until循环

  即do … while,重复执行循环体到循环条件为真时。

1
2
3
repeat
statements
until( condition )

break语句

  Lua支持break语句。

流程控制

  if语句的格式:

1
2
3
4
if(布尔表达式)
then
--[ 在布尔表达式为 true 时执行的语句 --]
end

  if … else 语句格式:

1
2
3
4
5
6
if(布尔表达式)
then
--[ 布尔表达式为 true 时执行该语句块 --]
else
--[ 布尔表达式为 false 时执行该语句块 --]
end

  需要注意的是,Lua中0也为真值,只有false和nil为假。

函数

定义

  Lua中,函数的标准格式如下:

1
2
3
4
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
end
  1. optional_function_scope这个参数是可选的,表示函数是全局的还是局部的。默认为全局函数,设置为局部函数需要加关键字local
  2. function_name函数名
  3. argument函数的参数,用逗号隔开,也可以不带参数
  4. function_body函数体
  5. result_params_comma_separated返回值,可以有多个。

  函数可以作为参数

多返回值

  Lua中的函数可以有多个返回值。

1
return res1,res2;

可变参数

  Lua中的函数可以接受可变数目的参数,用三点来代表多个参数。计算平均值的程序,可以这样写:

1
2
3
4
5
6
7
8
9
10
11
function average(...)
result = 0
local arg={...}
for i,v in ipairs(arg) do
result = result + v
end
print("总共传入 " .. #arg .. " 个数")
return result/#arg
end
print("平均值为",average(10,5,3,4,5,6))

  在新的版本里,#不能用于返回数组元素的个数了,而是需要使用:

1
select("#",...)

运算符

算数运算符

  常用的算术运算符与其他语言类似。需要注意的是,Lua里没有整数,所以如果想要取整操作,必须要进行取整操作:

1
x = math.ceil(x)

  需要注意的是,这里的取整仍然是向上取整。也就是说,无论小数部分有多小,取整的结果都是要比原数的整数部分大1。

  除此之外,常用的操作应该还有数据精度的控制:

1
string.format("%.2f",dt)

关系运算符

符号 含义
== 等于
~= 不等
>= 大于等于
<= 小于等于
> 大于
< 小于

逻辑运算符

符号 含义
and
or
not

其他运算符

符号 含义
.. 连结两个字符串
# 返回字符串或表的长度

  #运算符,获取的表的长度实际上获取的是表最大的索引值。

1
2
3
4
5
6
7
8
9
10
11
12
13
tab1 = {"1","2"}
print("tab1长度"..#tab1)
tab2 = {key1="1","2"}
print("tab2长度"..#tab2)
tab3 = {}