标签:
官方网站:http://www.lua.org/
三方模块:https://luarocks.org/
Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua 有一个同时进行的JIT项目,提供在特定平台上的即时编译功能。
Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,ini等文件格式,并且更容易理解和维护。Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gzz代表gzip的压缩包;x代表解压;v代表显示过程信息;f代表后面接的是文件
cd lua-5.3.0
make linux test
make install
注意
报 lua.c:67:31: fatal error: readline/readline.h: No such file or directory,说明缺少libreadline-dev依赖包
centos: yum install readline-devel
debian: apt-get install libreadline-dev.
安装完成之后,Lua 提供了交互式编程模式。我们可以在命令行中输入程序并立即查看效果。
$ lua -i
$ Lua 5.3.2 Copyright (C) 1994-2015 Lua.org, PUC-Rio
luarocks可以安装和更新lua的第三方模块。
可以在 http://luarocks.org/releases/ 页面选择需要的软件包。
安装教程:https://github.com/keplerproject/luarocks/wiki/Installation-instructions-for-Unix
两个减号是单行注释:
print("Hello World!")--这个是单行注释
多行注释
--[[print("Hello World!")print("Hello World!")--]]
Lua 表示符用于定义一个变量,函数获取其他用户定义的项。标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上0个或多个字母,下划线,数字(0到9)。
最好不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。
Lua 不允许使用特殊字符如 @, $, 和 % 来定义标示符。 Lua 是一个区分大小写的编程语言。因此在 Lua 中 W3c 与 w3c 是两个不同的标示符。
and break do else elseif end false for function if in local nil not or repeat return then true until while
在默认情况下,变量总是认为是全局的。
全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。
换句话说, 当且仅当一个变量不等于nil时,这个变量即存在。
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。
| 数据类型 | 描述 |
|---|---|
| nil | 只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
| boolean | 包含两个值:false和true。 |
| number | 表示双精度类型的实浮点数 |
| string | 字符串由一对双引号或单引号来表示,用..来拼接字符串 |
| function | 由 C 或 Lua 编写的函数 |
| userdata | 表示任意存储在变量中的C数据结构 |
| thread | 表示执行的独立线路,用于执行协同程序 |
| table | Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。 |
变量在使用前,必须在代码中进行声明,即创建该变量。编译程序执行代码之前编译器需要知道如何给语句变量开辟存储区,用于存储变量的值。
Lua 变量有三种类型:全局变量、局部变量、表中的域。
函数外的变量默认为全局变量,除非用 local 显示声明。函数内变量与函数的参数默认为局部变量。
局部变量的作用域为从声明位置开始到所在语句块结束(或者是直到下一个同名局部变量的声明)。
变量的默认值均为 nil。
Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。注意:如果要对多个变量赋值必须依次对每个变量赋值。
a, b = 10, 2x <–> a=10; b=2x
遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:
x, y = y, x – swap ‘x’ for ‘y’
a[i], a[j] = a[j], a[i] – swap ‘a[i]’ for ‘a[i]’
函数调用返回给变量
a, b = f()
f()返回两个值,第一个赋给a,第二个赋给b。
对 table 的索引使用方括号 []
t[i]
t.i – 当索引为字符串类型时的一种简化写法
gettable_event(t,i) – 采用索引访问本质上是一个类似这样的函数调用
while(condition)dostatementsend--var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1。for var=exp1,exp2,exp3 do<执行体>endfor i=10,1,-1 doprint(i)end--打印数组a的所有值 ,i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。for i,v in ipairs(a) doprint(v)endrepeatstatementswhile( condition )
循环控制语句
break 退出当前循环或语句,并开始脚本执行紧接着的语句。
控制结构的条件表达式结果可以是任何值,Lua认为false和nil为假,true 和非nil为真。
要注意的是Lua中 0 为 true
if(布尔表达式)then--[ 在布尔表达式为 true 时执行的语句 --]else--[ 布尔表达式为 false 时执行该语句块 --]end
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)function_bodyreturn result_params_comma_separatedend
optional_function_scope
该参数是可选的制定函数是全局函数还是局部函数,未设置该参数末尾为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
result_params_comma_separated
函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
function average(...)result = 0local arg={...}for i,v in ipairs(arg) doresult = result + vendprint("总共传入 " .. #arg .. " 个数")return result/#argend
Lua函数可以接受可变数目的参数,和C语言类似在函数参数列表中使用三点(…) 表示函数有可变的参数。
Lua将函数的参数放在一个叫arg的表中,#arg 表示传入参数的个数。
例如,我们计算几个数的平均值:
print(“平均值为”,average(10,5,3,4,5,6))
算术运算符
所有语言通用+-*/^%
关系运算符
所有语言通用,特例:不等于为~=
逻辑运算符
设定 A 的值为 true,B 的值为 false:
(A and B) 为 false。
(A or B) 为 true。
not(A and B) 为 true。
其他运算符
.. 连接两个字符串
优先级
从高到低的顺序:
^
not - (unary)
* /
+ -
..
< > <= >= ~= ==
and
or
除了^和..外所有的二元运算符都是左连接的。
字符串或串(String)是由数字、字母、下划线组成的一串字符。
Lua 语言中字符串可以使用以下三种方式来表示:
string1 = "Lua"print("\"字符串 1 是\"",string1)string2 = ‘w3cschool.cc‘print("字符串 2 是",string2)string3 = [["Lua 教程"]]print("字符串 3 是",string3)

泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
for k, v in pairs(t) doprint(k, v)end
范性for的执行过程:
首先,初始化,计算in后面表达式的值,表达式应该返回范性for需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
第三,将迭代函数返回的值赋给变量列表。
第四,如果返回的第一个值为nil循环结束,否则执行循环体。
第五,回到第二步再次调用迭代函数
无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。
每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。
function square(iteratorMaxCount,currentNumber)if currentNumber<iteratorMaxCountthencurrentNumber = currentNumber+1return currentNumber, currentNumber*currentNumberendendfor i,n in square,3doprint(i,n)end
很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到table内,将table作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在table内,所以迭代函数通常不需要第二个参数。
array = {"Lua", "Tutorial"}function elementIterator (collection)local index = 0local count = #collection-- 闭包函数return function ()index = index + 1if index <= countthen-- 返回迭代器的当前元素return collection[index]endendendfor element in elementIterator(array)doprint(element)end
table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数字、字典等。
Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
Lua table 是不固定大小的,你可以根据自己需要进行扩容。
Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用”format”来索引table string。
-- 初始化表mytable = {}-- 指定值mytable[1]= "Lua"-- 移除引用mytable = nil-- lua 垃圾回收会释放内存
当我们初始化 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。
模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。
-- 文件名为 module.lua-- 定义一个名为 module 的模块module = {}-- 定义一个常量module.constant = "这是一个常量"-- 定义一个函数function module.func1()io.write("这是一个公有函数!\n")end--表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.local function func2()print("这是一个私有函数!")endfunction module.func3()func2()endreturn module
Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。
require(“<模块名>”)或者require “<模块名>”
-- test_module.php 文件-- module 模块为上文提到到 module.luarequire("module")print(module.constant)module.func3()-- test_module2.php 文件-- module 模块为上文提到到 module.lua-- 别名变量 mlocal m = require("module")print(m.constant)m.func3()
对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。
require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 “~/lua/” 路径加入 LUA_PATH 环境变量里:
#LUA_PATH
export LUA_PATH=”~/lua/?.lua;;”
文件路径以 “;” 号分隔,最后的 2 个 “;;” 表示新加的路径后面加上原来的默认路径。
接着,更新环境变量参数,使之立即生效。
source ~/.profile
这时假设 package.path 的值是:
/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua
那么调用 require(“module”) 时就会尝试打开以下文件目录去搜索目标。
/Users/dengjoe/lua/module.lua;
./module.lua
/usr/local/share/lua/5.1/module.lua
/usr/local/share/lua/5.1/module/init.lua
/usr/local/lib/lua/5.1/module.lua
/usr/local/lib/lua/5.1/module/init.lua
如果找过目标文件,则会调用 package.loadfile 来加载模块。否则,就会去找 C 程序库。
搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。
搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。
Lua和C是很容易结合的,使用C为Lua写包。
与Lua中写包不同,C包在使用以前必须首先加载并连接,在大多数系统中最容易的实现方式是通过动态连接库机制。
Lua在一个叫loadlib的函数内提供了所有的动态连接的功能。这个函数有两个参数:库的绝对路径和初始化函数。所以典型的调用的例子如下:
local path = “/usr/local/lua/lib/libluasocket.so”
local f = loadlib(path, “luaopen_socket”)
loadlib函数加载指定的库并且连接到Lua,然而它并不打开库(也就是说没有调用初始化函数),反之他返回初始化函数作为Lua的一个函数,这样我们就可以直接在Lua中调用他。
如果加载动态库或者查找初始化函数时出错,loadlib将返回nil和错误信息。我们可以修改前面一段代码,使其检测错误然后调用初始化函数:
local path = “/usr/local/lua/lib/libluasocket.so”
– 或者 path = “C:\windows\luasocket.dll”,这是 Window 平台下
local f = assert(loadlib(path, “luaopen_socket”))
f() – 真正打开库
一般情况下我们期望二进制的发布库包含一个与前面代码段相似的stub文件,安装二进制库的时候可以随便放在某个目录,只需要修改stub文件对应二进制库的实际路径即可。
将stub文件所在的目录加入到LUA_PATH,这样设定后就可以使用require函数加载C库了。
在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。
因此 Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。
例如,使用元表我们可以定义Lua如何计算两个table的相加操作a+b。
当Lua试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫”__add”的字段,若找到,则调用对应的值。”__add”等即时字段,其对应的值(往往是一个函数或是table)就是”元方法”。
有两个很重要的函数来处理元表:
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
| 方法 | 描述 |
|---|---|
| coroutine.create() | 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用 |
| coroutine.resume() | 重启coroutine,和create配合使用 |
| coroutine.yield() | 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果 |
| coroutine.status() | 查看coroutine的状态,注:coroutine的状态有三种:dead,suspend,running |
| coroutine.wrap() | 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复 |
| coroutine.running() | 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号 |
coroutine在底层实现就是一个线程。
当create一个coroutine的时候就是在新线程中注册了一个事件。
当使用resume触发事件的时候,create的coroutine函数就被执行了,当遇到yield的时候就代表挂起当前线程,等候再次resume触发事件。
function foo (a)print("foo 函数输出", a)return coroutine.yield(2 * a) -- 返回 2*a 的值endco = coroutine.create(function (a , b)print("第一次协同程序执行输出", a, b) -- co-body 1 10local r = foo(a + 1)print("第二次协同程序执行输出", r)local r, s = coroutine.yield(a + b, a - b) -- a,b的值为第一次调用协同程序时传入print("第三次协同程序执行输出", r, s)return b, "结束协同程序" -- b的值为第二次调用协同程序时传入end)print("main", coroutine.resume(co, 1, 10)) -- true, 4print("--分割线----")print("main", coroutine.resume(co, "r")) -- true 11 -9print("---分割线---")print("main", coroutine.resume(co, "x", "y")) -- true 10 endprint("---分割线---")print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutineprint("---分割线---")--结果第一次协同程序执行输出 1 10foo 函数输出 2main true 4--分割线----第二次协同程序执行输出 rmain true 11 -9---分割线---第三次协同程序执行输出 x ymain true 10 结束协同程序---分割线---main false cannot resume dead coroutine---分割线---
resume和yield的配合强大之处在于,resume处于主程中,它将外部状态(数据)传入到协同程序内部;而yield则将内部的状态(数据)返回到主程中。
local newProductorfunction productor()local i = 0while true doi = i + 1send(i) -- 将生产的物品发送给消费者endendfunction consumer()while true dolocal i = receive() -- 从生产者那里得到物品print(i)endendfunction receive()local status, value = coroutine.resume(newProductor)return valueendfunction send(x)coroutine.yield(x) -- x表示需要发送的值,值返回以后,就挂起该协同程序end-- 启动程序newProductor = coroutine.create(productor)consumer()
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
file = io.open (filename [, mode])
| 模式 | 描述 |
|---|---|
| r | 以只读方式打开文件,该文件必须存在。 |
| w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 |
| a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
| r+ | 以可读写方式打开文件,该文件必须存在。 |
| w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
| a+ | 与a类似,但此文件可读可写 |
| b | 二进制模式,如果文件是二进制文件,可以加上b |
| + | 号表示对文件既可以读也可以写 |
-- 以只读方式打开文件file = io.open("test.lua", "r")-- 设置默认输入文件为 test.luaio.input(file)-- 输出文件第一行print(io.read())-- 关闭打开的文件io.close(file)-- 以附加的方式打开只写文件file = io.open("test.lua", "a")-- 设置默认输出文件为 test.luaio.output(file)-- 在文件最后一行添加 Lua 注释io.write("-- test.lua 文件末尾注释")-- 关闭打开的文件io.close(file)
通常我们需要在同一时间处理多个文件。我们需要使用 file:function_name 来代替 io.function_name 方法。
-- 以只读方式打开文件file = io.open("test.lua", "r")-- 输出文件第一行print(file:read())-- 关闭打开的文件file:close()-- 以附加的方式打开只写文件file = io.open("test.lua", "a")-- 在文件最后一行添加 Lua 注释file:write("--test")-- 关闭打开的文件file:close()
任何程序语言中,都需要错误处理。错误类型有:
local function add(a,b)assert(type(a) == "number", "a 不是一个数字")assert(type(b) == "number", "b 不是一个数字")return a+bendadd(10)
实例中assert首先检查第一个参数,若没问题,assert不做任何事情;否则,assert以第二个参数作为错误信息抛出。
lua: test.lua:3: b 不是一个数字
stack traceback:
[C]: in function ‘assert’
test.lua:3: in local ‘add’
test.lua:6: in main chunk
[C]: in ?
error (message [, level])
功能:终止正在执行的函数,并返回message的内容作为错误信息(error函数永远都不会返回)
通常情况下,error会附加一些错误位置的信息到message头部。
Level参数指示获得错误的位置:
pcall接收一个函数和要传递个后者的参数,并执行,执行结果:有错误、无错误;返回值true或者或false, errorinfo。
> =pcall(function(i) print(i) end, 33)
33
true
> =pcall(function(i) print(i) error(‘error..’) end, 33)
33
false stdin:1: error..
pcall以一种”保护模式”来调用第一个参数,因此pcall可以捕获函数执行中的任何错误。
通常在错误发生时,希望落得更多的调试信息,而不只是发生错误的位置。但pcall返回时,它已经销毁了调用桟的部分内容。
Lua提供了xpcall函数,xpcall接收第二个参数——一个错误处理函数,当错误发生时,Lua会在调用桟展看(unwind)前调用错误处理函数,于是就可以在这个函数中使用debug库来获取关于错误的额外信息了。
debug库提供了两个通用的错误处理函数:
xpcall(function(i) print(i) error(‘error..‘) end, function() print(debug.traceback()) end, 33)--33 stack traceback: stdin:1: in function [C]: in function ‘error‘ stdin:1: in function [C]: in function ‘xpcall‘ stdin:1: in main chunk [C]: in ? false nilfunction myfunction ()n = n/nilendfunction myerrorhandler( err )print( "ERROR:", err )endstatus = xpcall( myfunction, myerrorhandler )print( status)--ERROR: test2.lua:2: attempt to perform arithmetic on global ‘n‘ (a nil value) false
命令行调试器有:RemDebug、clidebugger、ctrace、xdbLua、LuaInterface - Debugger、Rldb、ModDebug。
图形界调试器有:SciTE、Decoda、ZeroBrane Studio、akdebugger、luaedit。
Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。
Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。
Lua 实现了一个增量标记-扫描收集器。 它使用这两个数字来控制垃圾收集循环: 垃圾收集器间歇率和垃圾收集器步进倍率。 这两个数字都使用百分数为单位 (例如:值 100 在内部表示 1 )。
垃圾收集器间歇率控制着收集器需要在开启新的循环前要等待多久。 增大这个值会减少收集器的积极性。 当这个值比 100 小的时候,收集器在开启新的循环前不会有等待。 设置这个值为 200 就会让收集器等到总内存使用量达到 之前的两倍时才开始新的循环。
垃圾收集器步进倍率控制着收集器运作速度相对于内存分配速度的倍率。 增大这个值不仅会让收集器更加积极,还会增加每个增量步骤的长度。 不要把这个值设得小于 100 , 那样的话收集器就工作的太慢了以至于永远都干不完一个循环。 默认值是 200 ,这表示收集器以内存分配的”两倍”速工作。
如果你把步进倍率设为一个非常大的数字 (比你的程序可能用到的字节数还大 10% ), 收集器的行为就像一个 stop-the-world 收集器。 接着你若把间歇率设为 200 , 收集器的行为就和过去的 Lua 版本一样了: 每次 Lua 使用的内存翻倍时,就做一次完整的收集。
Lua 提供了以下函数collectgarbage ([opt [, arg]])用来控制自动内存管理:
面向对象特征
1) 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
2) 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
3) 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
4)抽象:抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。
我们知道,对象由属性和方法组成。LUA中最基本的结构是table,所以需要用table来描述对象的属性。
lua中的function可以用来表示方法。那么LUA中的类可以通过table + function模拟出来。
至于继承,可以通过metetable模拟出来(不推荐用,只模拟最基本的对象大部分时间够用了)。
Lua中的表不仅在某种意义上是一种对象。像对象一样,表也有状态(成员变量);也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。
-- Meta classShape = {area = 0}-- 基础类方法 newfunction Shape:new (o,side)o = o or {}setmetatable(o, self)self.__index = selfside = side or 0self.area = side*side;return oend-- 基础类方法 printAreafunction Shape:printArea ()print("面积为 ",self.area)end-- 创建对象myshape = Shape:new(nil,10)myshape:printArea()Square = Shape:new()-- 派生类方法 newfunction Square:new (o,side)o = o or Shape:new(o,side)setmetatable(o, self)self.__index = selfreturn oend-- 派生类方法 printAreafunction Square:printArea ()print("正方形面积为 ",self.area)end-- 创建对象mysquare = Square:new(nil,10)mysquare:printArea()Rectangle = Shape:new()-- 派生类方法 newfunction Rectangle:new (o,length,breadth)o = o or Shape:new(o)setmetatable(o, self)self.__index = selfself.area = length * breadthreturn oend-- 派生类方法 printAreafunction Rectangle:printArea ()print("矩形面积为 ",self.area)end-- 创建对象myrectangle = Rectangle:new(nil,10,20)myrectangle:printArea()
LuaSQL。他是开源的,支持的数据库有:ODBC, ADO, Oracle, MySQL, SQLite 和 PostgreSQL。
require "luasql.mysql"--创建环境对象env = luasql.mysql()--连接数据库conn = env:connect("数据库名","用户名","密码","IP地址",端口)--设置数据库的编码格式conn:execute"SET NAMES UTF8"--执行数据库操作cur = conn:execute("select * from role")row = cur:fetch({},"a")--文件对象的创建file = io.open("role.txt","w+");while row dovar = string.format("%d %s\n", row.id, row.name)print(var)file:write(var)row = cur:fetch(row,"a")endfile:close() --关闭文件对象conn:close() --关闭数据库连接env:close() --关闭数据库环境
菜鸟教程:http://www.runoob.com/lua/lua-tutorial.html
标签:
原文地址:http://www.cnblogs.com/leestar54/p/5258172.html