lua语言
(一)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可以使用它们,就像是本来就内置的功能一样。
其它特性:
a.支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
b.语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
c.通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。
Lua应用场景:
游戏开发
独立应用脚本
Web 应用脚本
扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
安全系统,如入侵检测系统
-------------------------------------
(二)Linux系统上安装:
Linux安装Lua需要下载源码包并在终端解压编译即可,本文使用了5.3.0版本进行安装:
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install
(三)Lua基本语法
创建一个 HelloWorld.lua 文件,代码如下:
[root@crmn LuaTest]# lua HelloWorld.lua
hello lua!
[root@crmn LuaTest]# cat HelloWorld.lua
print("hello lua!")
//交互式编程:
[root@crmn LuaTest]# lua -i
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print("heheda!")
heheda!
>
//脚本式编程:
[root@crmn LuaTest]# cat HelloWorld.lua
print("hello lua!")
print("www.runoob.com")
[root@crmn LuaTest]# lua HelloWorld.lua
hello lua!
www.runoob.com
//将代码修改为如下形式来执行脚本(在开头添加:#!/usr/bin/lua):
[root@crmn LuaTest]# cat HelloWorld.lua
[root@crmn LuaTest]# cat HelloWorld.lua
#!/usr/bin/lua
print("hello lua!") --hello //单行注释
print("www.runoob.com") --[[ //多行注释
www.
--]]
[root@crmn LuaTest]# chmod +x HelloWorld.lua
[root@crmn LuaTest]# ./HelloWorld.lua
hello lua!
www.runoob.com
//标识符
Lua表示符用于定义一个变量,函数获取其他用户定义的项。标示符以一个字母A到Z或a到z或下划线_开头后加上0个或多个字母,下划线,数字(0到9)。
Lua是一个区分大小写的编程语言。
//关键字
and break do else
elseif end false for
function if in local
nil not or repeat
return then true until
while
//全局变量:
在默认情况下,变量总是认为是全局的。
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。
[root@crmn LuaTest]# lua -i
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(b)
nil
> b=12
> print(b)
12
>
> b=nil
> print(b)
nil
//如果你想删除一个全局变量,只需要将变量赋值为nil这样变量b就好像从没被使用过一样。换句话说,当且仅当一个变量不等于nil时,这个变量即存在。
//一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。
--------------------------------------
(四)Lua 数据类型:
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。值可以存储在变量中,作为参数传递或结果返回。
lua中有8个基本类型分别为:
nil: 只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
//nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值
boolean:包含两个值:false和true。
//boolean类型只有两个可选值:true(真)和false(假),Lua把false和nil看作是"假",其他的都为"真"。
number: 表示双精度类型的实浮点数。
//Lua 默认只有一种 number 类型 -- double(双精度)类型(默认类型可以修改 luaconf.h 里的定义)
string:字符串由一对双引号或单引号来表示。
//也可以用 2 个方括号 "[[]]" 来表示"一块"字符串。
在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字
userdata:表示任意存储在变量中的C数据结构
function:由 C 或 Lua 编写的函数。
thread:表示执行的独立线路,用于执行协同程序。
table:Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。在Lua里,table的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。
我们可以使用type函数测试给定变量或者值的类型:
> print(type("hello world!"))
string
> print(type(10.4*2))
number
> print(type(print))
function
> print(type(true))
boolean
> print(type(type))
function
> print(type(nil))
nil
> print(type(type(x)))
string
说明:
//string(字符串):
> print("2"+3)
5
> print("2"+"3")
5
> print("-2e2"*"3")
-600
> print("a"..'bc')
abc
> print("123"..'456')
123456
>
> len="helloworld"
> print(#len)
10
> print(#helloworld)
stdin:1: attempt to get length of global 'helloworld' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?
> print(#"helloworld")
10
//table(表):
//Lua中的表(table)其实是一个"关联数组"(associativearrays),数组的索引可以是数字或者是字符串。
[root@crmn LuaTest]# cat table_test.lua
local tbl1={}
local tbl2={"apple","pear","orange","grape"}
a={}
a["key"]="value"
key=10
a[key]=12
a[key]=a[key]+11
for k,v in pairs(a) do
print(k ..":" ..v)
end
[root@crmn LuaTest]# lua table_test.lua
key:value
10:23
//不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。
[root@crmn LuaTest]# cat table_test2.lua
local tb1 = {"apple","pear","orange","grape"}
for key,val in pairs(tb1) do
print("key:", key)
end
[root@crmn LuaTest]# lua table_test2.lua
key: 1
key: 2
key: 3
key: 4
//table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。
[root@crmn LuaTest]# cat table_test3.lua
a3={}
for i=1,10 do
a3[i]=i
end
a3["key"]="val"
print(a3["key"])
print(a3["none"])
[root@crmn LuaTest]# lua table_test3.lua
val
nil
//function(函数):
//在Lua中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里
[root@crmn LuaTest]# cat function_test.lua
function factorial1(n)
if n==0 then
return 1
else
return n*factorial1(n-1)
end
end
print(factorial1(5))
factorial2=factorial1
print(factorial2(5))
[root@crmn LuaTest]# lua function_test.lua
120
120+
//function 可以以匿名函数(anonymous function)的方式通过参数传递
[root@crmn LuaTest]# cat function_test2.lua
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
);
[root@crmn LuaTest]# lua function_test2.lua
key1=val1
key2=val2
//thread(线程):
在Lua里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
//userdata(自定义类型):
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。
(六)Lua循环:
Lua语言提供了以下几种循环处理方式:
while循环:在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for循环:重复执行指定语句,重复次数可在for语句中控制。
repeat...until:重复执行循环,直到指定的条件为真时为止。
循环嵌套:可以在循环内嵌套一个或多个循环语句(while do ... end;for ... do ... end;repeat ... until;)
[root@crmn LuaTest]# cat while.lua
a=10
while( a<15 )
do
print("a:",a)
a=a+1
end
[root@crmn LuaTest]# lua while.lua
a: 10
a: 11
a: 12
a: 13
a: 14
Lua 编程语言中 for语句有两大类:
数值for循环
泛型for循环
[root@crmn LuaTest]# cat for1.lua //数值for循环;var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1
#!/usr/bin/lua
function f(x)
print("function...")
return x*2
end
for i=1,f(5) do print(i)
end
[root@crmn LuaTest]# lua for1.lua
function...
1
2
3
4
5
6
7
8
9
10
[root@crmn LuaTest]# cat for2.lua //泛型for循环;i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。
#!/usr/bin/lua
days={"sunday","monday","tuesday","wednesday","thursday","friday","saturday"}
for i,v in ipairs(days) do print(v)
end
[root@crmn LuaTest]# lua for2.lua
sunday
monday
tuesday
wednesday
thursday
friday
saturday
[root@crmn LuaTest]# cat until.lua
#!/usr/bin/lua
a=10
repeat
print("a:",a)
a=a+1
until(a>15)
[root@crmn LuaTest]# lua until.lua
a: 10
a: 11
a: 12
a: 13
a: 14
a: 15
[root@crmn LuaTest]# cat break.lua //Lua编程语言break语句插入在循环体中,用于退出当前循环或语句,并开始脚本执行紧接着的语句。
如果你使用循环嵌套,break语句将停止最内层循环的执行,并开始执行的外层的循环语句。
#!/usr/bin/lua
a=10
while(a<20)
do
print("a:",a)
a=a+1
if(a>15)
then
break
end
end
[root@crmn LuaTest]# lua break.lua
a: 10
a: 11
a: 12
a: 13
a: 14
a: 15
(七)Lua流程控制:
Lua编程语言流程控制语句通过程序设定一个或多个条件语句来设定。在条件为 true 时执行指定程序代码,在条件为 false 时执行其他指定代码。
控制结构的条件表达式结果可以是任何值,Lua认为false和nil为假,true和非nil为真。
(八)Lua函数:
在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。
Lua提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。
Lua函数主要有两种用途:
1.完成指定的任务,这种情况下函数作为调用语句使用;
2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。
函数定义:
Lua 编程语言函数定义格式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
end
解析:
optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
function_name: 指定函数名称。
argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
function_body: 函数体,函数中需要执行的代码语句块。
result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
[root@crmn LuaTest]# cat func1.lua//定义了函数max(),参数为num1, num2,用于比较两值的大小,并返回最大值
#!/usr/bin/lua
function max(num1,num2)
if(num1>num2)then
result = num1;
else
result = num2;
end
return result;
end
print("max:",max(10,4))
print("max:",max(5,6))
[root@crmn LuaTest]# lua func1.lua
max: 10
max: 6
[root@crmn LuaTest]# cat func2.lua //Lua中我们可以将函数作为参数传递给函数,如下实例:
#!/usr/bin/lua
myprint=function(param)
print("this is function:##",param,"##")
end
function add(num1,num2,functionPrint)
result=num1+num2
functionPrint(result) //调用传递的函数参数
end
myprint(10)
add(2,5,myprint)
[root@crmn LuaTest]# lua func2.lua
this is function:## 10 ##
this is function:## 7 ##
可变参数:
Lua函数可以接受可变数目的参数,和C语言类似在函数参数列表中使用三点(...) 表示函数有可变的参数。
Lua将函数的参数放在一个叫arg的表中,#arg 表示传入参数的个数。
[root@crmn LuaTest]# cat func3.lua
#!/usr/bin/lua
function average(...)
result=0
local arg={...}
for i,v in ipairs(arg) do
result=result+v
end
print("total:",#arg)
return result/#arg
end
print("averr:",average(10,5,3,4,5,6))
[root@crmn LuaTest]# lua func3.lua
total: 6
averr: 5.5
多返回值:
Lua函数可以返回多个结果值,比如string.find,其返回匹配串"开始和结束的下标"(如果不存在匹配串返回nil)。
[root@crmn LuaTest]# cat func4.lua
#!/usr/bin/lua
function maximum(a)
local mi=1
local m=a[mi]
for i,val in ipairs(a) do
if val > m then
mi = i
m = val
end
end
return m,mi
end
print(maximum({8,10,23,12,5}))
[root@crmn LuaTest]# lua func4.lua
23 3
------------------------------------------------------------
(九)Lua运算符
[root@crmn LuaTest]# cat 9_1.lua //算术运算符
a=21
b=10
c=a+b
print("line 1-c:",c)
c=a-b
print("line 2-c:",c)
c=a*b
print("line 3-c:",c)
c=a/b
print("line 4-c:",c)
c=a%b
print("line 5-c:",c)
c=a^2
print("line 6-c:",c)
c=-a
print("line 7-c:",c)
[root@crmn LuaTest]# lua 9_1.lua
line 1-c: 31
line 2-c: 11
line 3-c: 210
line 4-c: 2.1
line 5-c: 1
line 6-c: 441
line 7-c: -21
[root@crmn LuaTest]# cat 9_2.lua //关系运算符
a=21
b=10
if( a == b )
then
print("line 1:a == b")
else
print("line 2:a ~= b")
end
a=31
b=20
if( a >= b )
then
print("line 3:a >= b")
end
[root@crmn LuaTest]# lua 9_2.lua
line 2:a ~= b
line 3:a >= b
[root@crmn LuaTest]# cat 9_3.lua
a=true
b=true
if( a and b )
then
print("a and b:true")
end
if( a or b )
then
print("a or b:true")
end
if( not (a and b) )
then
print("not(a and b):true")
end
[root@crmn LuaTest]# lua 9_3.lua
a and b:true
a or b:true
[root@crmn LuaTest]# cat 9_4.lua //
a="hello"
b="leidi"
print("a..b:",a..b) //连接两个字符串
print("#b:",#b)
print("Test:",#"Test") //返回字符串或者表的长度
[root@crmn LuaTest]# lua 9_4.lua
a..b: helloleidi
#b: 5
Test: 4
运算符优先级
从高到低的顺序:
^
not - (unary)
* /
+ -
..
< > <= >= ~= ==
and
or
(十)Lua 字符串
字符串或串(String)是由数字、字母、下划线组成的一串字符。
Lua 语言中字符串可以使用以下三种方式来表示:
单引号间的一串字符。
双引号间的一串字符。
[[和]]间的一串字符。
[root@crmn LuaTest]# cat 10.lua
string1 = "lua"
print("string1:",string1)
string2 = 'helloworld'
print("string2:",string2)
string3 = [[meng...]]
print("string3:",string3)
[root@crmn LuaTest]# lua 10.lua
string1: lua
string2: helloworld
string3: meng...
(十一)Lua 数组
数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。
Lua 数组的索引键值可以使用整数表示,数组的大小不是固定的。
//我们可以使用整数索引来访问数组元素,如果知道的索引没有值则返回nil。
在 Lua 索引值是以 1 为起始,但你也可以指定 0 开始。
[root@crmn LuaTest]# cat 11_1.lua
array = {"lua","leidi"}
for i = 0,2 do
print(array[i])
end
[root@crmn LuaTest]# lua 11_1.lua
nil
lua
leidi
[root@crmn LuaTest]# cat 11_2.lua
array={}
for i=-2,2 do
array[i]=i*2
end
for i=-2,2 do
print(array[i])
end
[root@crmn LuaTest]# lua 11_2.lua
-4
-2
0
2
4
多维数组
多维数组即数组中包含数组或一维数组的索引键对应一个数组。
(十二)Lua 迭代器
迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址
在Lua中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。
泛型for迭代器:
泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
[root@crmn LuaTest]# cat 12_1.lua //使用了Lua默认提供的迭代函数ipairs。
array = {"haha","heheda"}
for key,value in ipairs(array)
do
print(key,value)
end
[root@crmn LuaTest]# lua 12_1.lua
1 haha
2 heheda
下面我们看看范性for的执行过程:
首先,初始化,计算in后面表达式的值,表达式应该返回范性for需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
第三,将迭代函数返回的值赋给变量列表。
第四,如果返回的第一个值为nil循环结束,否则执行循环体。
第五,回到第二步再次调用迭代函数
在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。Lua 的迭代器包含以下两种类型:
无状态的迭代器
多状态的迭代器
(十三)lua table(表)
table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数字、字典等。
Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
Lua table 是不固定大小的,你可以根据自己需要进行扩容。
Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。
table(表)的构造:
构造器是创建和初始化表的表达式。表是Lua特有的功能强大的东西。最简单的构造函数是{},用来创建一个空表。可以直接初始化数组:
mytable = {} //初始化表
mytable[1] = "lua" //指定值
mytable = nil //lua垃圾回收会释放内存
当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。
(十四)Lua模块与包
模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下:
[root@crmn LuaTest]# cat module.lua
module = {}
module.constant = "a constant"
function module.func1()
io.write("function!\n")
end
local function func2()
print("private function!\n")
end
function module.func3()
func2()
end
return module
[root@crmn LuaTest]# cat test_module.lua
require("module")
print(module.constant)
module.func3()
[root@crmn LuaTest]# lua test_module.lua
a constant
private function!
[root@crmn LuaTest]# cat test_module2.lua //或者给加载的模块定义一个别名变量,方便调用
local m = require("module")
print(m.constant)
m.func3()
[root@crmn LuaTest]# lua test_module2.lua
a constant
private function!
由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。
上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.
require 函数
Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。例如:
require("<模块名>")
或者
require "<模块名>"
执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。
加载机制
对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。
require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
(十六)Lua文件I/O
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作。
完全模式(complete model) 使用外部的文件句柄来实现。它以一种面对对象的形式,将所有的文件操作定义为文件句柄的方法
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。
打开文件操作语句如下:
file=io.open(filename [,mode])
mode 的值有:
模式 描述
r 以只读方式打开文件,该文件必须存在。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
r+ 以可读写方式打开文件,该文件必须存在。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a+ 与a类似,但此文件可读可写
b 二进制模式,如果文件是二进制文件,可以加上b
+ 号表示对文件既可以读也可以写
[root@crmn LuaTest]# cat test.lua
nihao
wohao
dajiahao
[root@crmn LuaTest]# cat file.lua
file=io.open("test.lua","r")
io.input(file)
print(io.read())
io.close(file)
file=io.open("test.lua","a")
io.output(file)
io.write("--test.lua zhushi")
io.close(file)
[root@crmn LuaTest]# lua file.lua //执行
nihao
[root@crmn LuaTest]# cat test.lua
nihao
wohao
dajiahao