Lua 是什么?
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。
设计目的
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 特性
- 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
- 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
-
其它特性:
- 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
- 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
- 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
- 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。
Lua 基本语法
Lua 学习起来非常简单,我们可以创建第一个 Lua 程序!
交互式编程:
Lua 提供了交互式编程模式。我们可以在命令行中输入程序并立即查看效果。
Lua 交互式编程模式可以通过命令 lua -i 或 lua 来启用:
$ lua -i
$ Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
>
在命令行中,输入以下命令:
> print("my name is jack lee")
接着我们按下回车键,输出结果如下:
> print("my name is jack lee")
my name is jack lee
脚本式编程:
我们可以将 Lua 程序代码编写到一个以 lua 结尾的文件,并执行,该模式称为脚本式编程,如我们将如下代码存储在名为 name.lua 的脚本文件中,并且将脚本放在D:盘
print("my name is jack!")
print("welcome learn lua follow teacher li!")
使用 lua 名执行以上脚本,输出打印结果
lua d:\Lua\name.lua
注释
单行注释
两个减号是单行注释:
--
多行注释
--[[
多行注释
多行注释
--]]
变量,函数命名规范
标示符表示一个变量,函数或其他定义项,命名规范以一个字母 A 到 Z 或 a 到 z 或下划线 _后加上字母,下划线 _数字(0到9)。建议不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。
一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。
Lua 不允许使用特殊字符如 @, $, 和 % 来定义成员名。 Lua 是一个区分大小写的编程语言。因此在 Lua 中 Run 与 run 是两个不同的标示符。以下列出了一些正确的标示符:
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 |
全局变量
在默认情况下,变量总是认为是全局的。
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。
> print(b)
nil
> b=10
> print(b)
10
>
你可以设置全局变量为空,只需要将变量赋值为nil。
b = nil
print(b) --> nil
这样变量b就好像从没被使用过一样。换句话说, 当且仅当一个变量不等于nil时,这个变量即存在。
Lua 数据类型
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。 (注:以下数据类型后续做详细讲解)
数据类型 |
描述 |
nil |
表示一个无效值(在条件表达式中相当于false)。 |
boolean |
包含两个值:false和true。 |
number |
表示双精度类型的实浮点数 |
string |
字符串由一对双引号或单引号来表示 "" '' |
function |
函数 |
userdata |
表示任意存储在变量中的C数据结构 |
thread |
表示执行的独立线程,用于执行协同程序 |
table |
Lua 中的表(table)其实是一个"关联数组",数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。 |
我们可以使用type函数测试给定变量或者值的类型:
在sublime编辑器中写下以下代码, 按Ctrl+B 编译。
_str="I am str"
_number=10.116
_bo=false
print(type(str))
print(type(_number))
print(type(_bo))
数据类型具体分析:
nil(空)
nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值:
> print(type(a))
nil
boolean(布尔)
boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是"假",其他的都为"真"
number(数字)
Lua 默认只有一种 number 类型 -- double(双精度)类型,以下几种写法都被看作是 number
print(type(2))
print(type(2.2))
print(type(0.2))
string(字符串)字符串由一对双引号或单引号来表示。
string1 = "this is string1"
string2 = 'this is string2'
也可以用 2 个方括号 "[ [ ] ]" 来表示"一块"字符串。
_str2=[[my name is jack!]]
print(_str2)
在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字:
print("1"+5) --6
print("1"+"6") --7
print("3+7") -- "3+7"
关于字符串拼接,使用.. 对字符串进行拼接
value=11
print("value="..value) --value=11
使用 # (井号)来计算字符串的长度,放在字符串前面,如下实例:
mail = "ukraine_lee@163.com"
print(#mail)
--19
Table(表)
在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是大括号{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"} --苹果,梨,橙子,葡萄
local tbl2={X=3,y=4} --指定键值初始化 X,Y是键,值是3,4
Lua 中的表(table)其实是一个"关联数组",数组的索引可以是数字或者是字符串。(类似字典)
_table_1={}
_table_1["str_key1"]="str_value"
_table_1["str_key2"]=2
nub_key1=1
_table_1[nub_key1]="value1"
nub_key2=2
_table_1[nub_key2]=13
_table_1[nub_key2]=_table_1[nub_key2]+1
for k,v in pairs(_table_1) do
print(k.."===="..v)
end
不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
print("Key", key)
end
-- 1 2 3 4
table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。
_table = {}
for i = 1, 10 do
_table[i] = i
end
-- for k,v in pairs(_table) do
-- print(k,v)
-- end
_table["key"] = "val"
print(_table["key"])
print(_table["none"])
for k,v in pairs(_table) do
print(k,v)
end
表函数的定义和使用:
tab={x=2,y=3}
function tab:setValue(m_x,m_y) --注意定义的时候使用了:冒号
tab.x=m_x
tab.y=m_y
end
tab:setValue(5,6) --注意,在调用的时候也必须和定义时一致使用冒号。
print(tab.x,tab.y)
function(函数)
函数的基本语法:
function function_name(n_value)
return n_value+1
end
print(function_name(7))
函数还可以像下面这样存在一个变量里:
function function_name(n_value)
return n_value+1
end
print(function_name(7))
func_self=function_name
print(func_self(5))
function 可以以匿名函数(anonymous function)的方式通过参数传递:
--首先写一个函数 有个2个参数 1是表 2是函数 --遍历表 取出键值
--打印调用func将 键值作为参数传递进func
function anonymous(tab,func)
for k,v in pairs(tab) do
print(func(k,v))
end
end
--调用anonymous 1参传入表,2参是匿名函数并且有执行内容,--内容是返回_k _v 注--意函数结尾需要有end
_table={key1="value1",key2="value2"}
anonymous(_table,function(_k,_v)
return _k,_v
end)
thread(线程)
在 Lua 里,最主要的线程是协同程序(coroutine)。拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
userdata(自定义类型)
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。(简单来说就是在LUA中用userdata表示其他语言的数据类型)
Lua 变量
变量在使用前,必须在代码中进行声明,即创建该变量,Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量,
局部变量的作用域为从声明位置开始到所在语句块结束,变量的默认值均为 nil。
variable_1=1 --全局
local variable_2 = 2 --局部
function function_name()
variable_3=3 --全局
local variable_4 = 4 --局部
return variable_3+variable_2--(注意 variable_2是在外面声明的局部变量,本质也是全局的)
end
print(function_name())
print("variable_3="..variable_3)
print("variable_4=",variable_4)-- 注意不能使用".."连接一个空值
赋值语句
赋值是改变一个变量的值和改变表域的最基本的方法。
value=1
strValue="str"
value_2=value+2
print(strValue)
---------------------------------------------------------
_table={n="n_vale",m="m_value"}
print(_table.n)
_table.n=11
print(_table.n)
Lua 循环
很多情况下我们需要做一些有规律性的重复操作,因此在程序中就需要重复执行某些语句。
一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件。
循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体。
循环语句是由循环体及循环的终止条件两部分组成的。
while 循环
Lua 编程语言中 while 循环语句在判断条件为 true 时会重复执行循环体语句。
语法
Lua 编程语言中 while 循环语法:(注意不同于C# 语句没有大括号)
while(condition)
do
statements
end
statements(循环体语句) 可以是一条或多条语句,condition(条件) 可以是任意表达式,在 condition(条件) 为 true 时执
实例:
a=1
while( a < 5 )
do
print("a 的值为:", a)
a = a+1
end
Lua for 循环
Lua 编程语言中 for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。
Lua 编程语言中 for语句有两大类:(注意与C#的for 循环有较明显区别)
第一种:数值for循环
for var=exp1,exp2,exp3 do
<执行体>
end
var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1。
实例:
for i=1,5 do
print(i)
end
---------------------------------------------------
function function_name(x)
return x*2
end
for i=1,function_name(3) do
print(i)
end
第二种:泛型for循环
泛型for循环通过一个迭代器函数来遍历所有值
在lua中pairs与ipairs两个迭代器的用法相近,但有一点是不一样的:
pairs可以遍历表中所有的key,包含索引,和自定义类型key
ipairs 仅可以遍历出具备索引的值
_table2={"Suanday","Monday"}
_table2["ukey"]="uvalue" --键值都是字符串
intkey=8
_table2[intkey]="uvalue" --键是number 值是字符串
for k,v in ipairs(_table2) do
print(k,v)
end
输出结果是 (table2 中仅具备索引的2个值被输出了)
-- 1 Suanday
-- 2 Monday
for k,v in pairs(_table2) do
print(k,v)
end
输出结果是(所有的键值均被输出)
--1 Suanday
--2 Monday
--ukey uvalue
--8 uvalue
Lua break 语句
Lua 编程语言 break 语句插入在循环体中,用于退出当前循环或语句,并开始脚本执行紧接着的语句。
如果你使用循环嵌套,break语句将停止最内层循环的执行,并开始执行的外层的循环语句。
a=1
while(a<6)
do
print(a)
a=a+1
if(a>3)
then
break
end --注意if语句需要关键字 then和end
end --这个 end 是while 语句的结束
无限循环
在循环体中如果条件永远为 true 循环语句就会永远执行下去,以下以 while 循环为例:
while( true )
do
print("循环将永远执行下去")
end
Lua if 语句
Lua if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。
Lua if 语句语法格式如下:
if(布尔表达式)
then
--[ 在布尔表达式为 true 时执行的语句 --]
end
a=1
if(a>0)
then
a=a+1
print(a)
end
if...else 语句
Lua if 语句可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码块。
Lua if...else 语句语法格式如下:
if(布尔表达式)
then
--[ 布尔表达式为 true 时执行该语句块 --]
else
--[ 布尔表达式为 false 时执行该语句块 --]
end
if...elseif...else 语句
Lua if 语句可以与 elseif...else 语句搭配使用, 在 if 条件表达式为 false 时执行 elseif...else 语句代码块,用于检测多个条件语句。
Lua if...elseif...else 语句语法格式如下:
if( 布尔表达式 1)
then
--[ 在布尔表达式 1 为 true 时执行该语句块 --]
elseif( 布尔表达式 2)
then
--[ 在布尔表达式 2 为 true 时执行该语句块 --]
elseif( 布尔表达式 3)
then
--[ 在布尔表达式 3 为 true 时执行该语句块 --]
else
--[ 如果以上布尔表达式都不为 true 则执行该语句块 --]
end
if...else 语句
Lua if 语句允许嵌套, 这就意味着你可以在一个 if 或 else if 语句中插入其他的 if 或 else if 语句。Lua if 嵌套语句语法格式如下:
if( 布尔表达式 1)
then
--[ 布尔表达式 1 为 true 时执行该语句块 --]
if(布尔表达式 2)
then
--[ 布尔表达式 2 为 true 时执行该语句块 --]
end
end
范例:
a=1
if(a>0) then a=a+1
if(a==2) then a=a+11
end
print(a)
end
Lua 函数
在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。
Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。
Lua 函数主要有两种用途:
1.完成指定的任务,这种情况下函数作为调用语句使用;
2.计算并返回值,这种情况下函数作为赋值语句的表达式使用
function returenMaxValue(v1,v2)
if(v1>v2)
then result=v1
else
result=v2
return result
end
end
print(returenMaxValue(11,19))
Lua 运算符
运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 其他运算符
算术运算符
下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为10,B 的值为 20:
操作符 |
描述 |
实例 |
+ |
加法 |
A + B 输出结果 30 |
- |
减法 |
A - B 输出结果 -10 |
* |
乘法 |
A * B 输出结果 200 |
/ |
除法 |
B / A w输出结果 2 |
% |
取余 |
B % A 输出结果 0 |
^ |
乘幂 |
A^2 输出结果 100 |
- |
负号 |
-A 输出结果v -10 |
关系运算符
下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为10,B 的值为 20:
操作符 |
描述 |
实例 |
== |
等于,检测两个值是否相等,相等返回 true,否则返回 false |
(A == B) 为 false。 |
~= |
不等于,检测两个值是否相等,相等返回 false,否则返回 true |
(A ~= B) 为 true。 |
> |
大于,如果左边的值大于右边的值,返回 true,否则返回 false |
(A > B) 为 false。 |
< |
小于,如果左边的值大于右边的值,返回 false,否则返回 true |
(A < B) 为 true。 |
>= |
大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false |
(A >= B) 返回 false。 |
<= |
小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false |
(A <= B) 返回 true。 |
逻辑运算符
下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:
操作符 |
描述 |
实例 |
and |
逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 |
(A and B) 为 false。 |
or |
逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 |
(A or B) 为 true。 |
not |
逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 |
not(A and B) 为 true。 |
其他运算符
下表列出了 Lua 语言中的连接运算符与计算表或字符串长度的运算符:
操作符 |
描述 |
实例 |
.. |
连接两个字符串 |
a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。 |
# |
一元运算符,返回字符串或表的长度。 |
#"Hello" 返回 5 |
Lua 字符串
字符串或串(String)是由数字、字母、下划线组成的一串字符。
Lua 语言中字符串可以使用以下三种方式来表示:
单引号间的一串字符。
双引号间的一串字符。
和[[ ]]间的一串字符。
范例:
str_1="stringtype_1"
str_2='stringtype_2'
str_3=[["stringtype_3"]]
print(str_1)
print(str_2)
print(str_3)
字符串操作
result=string.upper("upper") //字符串转大写
print(result)
result=string.lower("LOWER")//字符串转小写
print(result)
result=string.reverse("reverse ")//字符串翻转
print(result)
result=string.len("len")//字符串长度
print(result)
字符串格式化
Lua 提供了 string.format() 函数来生成具有特定格式的字符串, 函数的第一个参数是格式 , 之后是对应格式中每个代号的各种数据。
字符串格式化
str_1="aaa"
str_2="bbb"
result =string.format("%s,%s",str_1,str_2)
print(result)
日期格式化:
day=1
month=5
year=2017
date=string.format("日期:%02d/%02d/%03d",day,month,year)
print(date)
Lua 数组
数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。
Lua 数组的索引键值可以使用整数表示,数组的大小不是固定的。
array={"hu","hj"}
for i=0,2 do
print(array[i])
end
--nil
-- hu
-- hj
-- 我们发现上述代码,索引为0时,从输出了nil lua数组索引默认为1.
正如你所看到的,我们可以使用整数索引来访问数组元素,如果知道的索引没有值则返回nil。
在 Lua 索引值是以 1 为起始,但你也可以指定 0 开始。
除此外我们还可以以负数为数组索引值:
array={}
for i=-10,0 do
array[i]=i*2
print(array[i])
end
多维数组
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
-- 123
-- 246
-- 369
Lua 迭代器
泛型 for 迭代器
泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
泛型 for 迭代器提供了集合的 key/value 对,语法格式如下:
for k, v in pairs(t) do
print(k, v)
end
范例代码:
table={"huhu","jack","ukraine"}
for k,v in pairs(table) do
print(k,v)
end
Lua table(表)
table 是 Lua 的一种数据结构,用来帮助我们创建不同的数据类型,如:数字、字典等。
Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
Lua table 是不固定大小的,你可以根据自己需要进行扩容。
table(表)的构造
构造器是创建和初始化表的表达式。表是Lua特有的功能强大的东西。最简单的构造函数是{},用来创建一个空表。
-- 初始化表
mytable = {}
-- 指定值
mytable[1]= "Lua" --使用数字作为键
table["strKey"]="value" --使用字符串作为键的写法1
table.strKey="value" --使用字符串作为键的写法2
-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存
范例代码-1:
table={"value1","value2"}
table["other1"]="other_value1"
table["other2"]=" other_value2"
for k,v in pairs(table) do
print(k,v)
end
--1 value1
--2 value2
--other1 other_value1
--other2 other_value2
范例代码-2:
m_table={"a","b","c"}
print("m_table类型是=",type(m_table))
temp_table=m_table
print("temp_table指向m_table,temp_table[1]=",temp_table[1])
temp_table[1]="aa" --修改m_table[1]的值
temp_table=nil
print("释放temp_table后 m_table[1]=",m_table[1])
Table连接:
m_table={"a","b","c"}
temp=table.concat(m_table) --注意table是关键字
print(temp)
插入和移除:
插入:
m_table={"a","b","c"}
table.insert(m_table,"d")
print(m_table[4])
移除:
table.remove(m_table) --移除方法,会移除最后一个元素
for k,v in pairs(m_table) do
print(k,v)
end
排序:
字母排序:
str={"a","d","b","c"}
for k,v in pairs(str) do
print("排序前:"..k..":"..v)
end
table.sort(str)
for k,v in pairs(str) do
print("排序后:"..k..":"..v)
end
数字排序:
a=1
b=2
c=3
d=4
str={a,d,b,c}
for k,v in pairs(str) do
print("排序前:"..k..":"..v)
end
table.sort(str)
for k,v in pairs(str) do
print("排序后:"..k..":"..v)
end