文章目录
  1. Lua 应用场景
  2. Hello world!
  3. 注释
  4. 变量
    1. 全局变量
    2. 局部变量
    3. 赋值
    4. 索引
  5. 数据类型
    1. nil
    2. bool类型
    3. number
    4. string
    5. table(表)
    6. function(函数)
    7. thread(线程)
    8. userdata(自定义类型)
  6. 循环
    1. while
    2. for
    3. 泛型for循环
    4. repeat…until(类似do while)
    5. 不同循环可以嵌套
    6. break
  7. 流程控制
  8. 函数
    1. 函数作为参数
    2. 多返回值
    3. 可变参数
  9. 运算符
    1. 算数
    2. 关系
    3. 逻辑
    4. 特殊
  10. 字符串
    1. 示例
    2. 字符串常用操作
  11. 数组
    1. 一维
    2. 多维
  12. 迭代器
    1. 内置简单迭代
    2. 自定义的迭代器
    3. 利用闭包实现的迭代器
  13. Lua table
    1. 初始化与销毁
    2. table的引用(类似Java)
    3. table操作
    4. !!!慎用”#table”
  14. 模块与包
    1. 自定义包
    2. 加载策略
  15. 元表
    1. __index
    2. __newindex
    3. __add
    4. __call
    5. __tostring
  16. 协同(coroutine)
    1. resume与create的配合 注意resume与yield的参数传递
    2. 生产者-消费者
  17. IO
    1. 简单模式(类c语言)
      1. 其他的IO函数
    2. 完全模式 IO.xxx变为file.xxx
  18. 错误处理
    1. assert与error
    2. pcall与xpcall
  19. 垃圾回收 lua为自动垃圾回收
  20. 面向对象
    1. 继承与方法重写


Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。

Lua 应用场景

游戏开发
独立应用脚本
Web 应用脚本
扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
安全系统,如入侵检测系统

Hello world!

1
print("Hello World")

注释

1
2
3
4
--行注释
--[[
块注释
--]]

变量

全局变量

默认即为全局变量,无需声明符号 访问未定义的全局变量不出错
*删除全局变量将其赋值为nil(等同于其他语言NULL)即可

1
2
3
4
5
a=10 --全局变量
print(a) --10
a=nil --删除该变量
print(a) --nil

局部变量

  • 局部变量的作用域为从声明位置开始到所在语句块结束(或者是直到下一个同名局部变量的声明)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    local data = 100;
    local function fun1()
    print(data);
    data = data+50;
    end
    data = 200;
    local data = 300; -- 重新定义一个局部变量
    local function fun2()
    print(data);
    data = data+50;
    end
    data = 400;
    --调用
    fun1(); -- 200
    fun2(); -- 400
    fun1(); -- 250
    fun2(); -- 450

赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a, b = 10, 2*x
x, y = y, x -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i] -- swap 'a[i]' for 'a[i]'
-[[赋值多个的时候,如下规则
a. 变量个数 > 值的个数 按变量个数补足nil
b. 变量个数 < 值的个数 多余的值会被忽略
]]
a, b, c = 0, 1
print(a,b,c) --> 0 1 nil
a, b = a+1, b+1, b+2 -- value of b+2 is ignored
print(a,b) --> 1 2
a, b, c = 0 --> 易错!注意!!!
print(a,b,c) --> 0 nil nil

索引

1
2
3
t[i]
t.i -- 当索引为字符串类型时的一种简化写法
gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用

数据类型

类型 说明
nil 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean 包含两个值:false和true。
number 表示双精度类型的实浮点数
string 字符串由一对双引号或单引号来表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的C数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。
1
2
3
4
5
6
7
8
--可用type查看类型
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 值:

1
print(type(a)) -- nil

对于全局变量和 table,nil 还有一个”删除”作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉,执行下面代码就知:

1
2
3
4
5
6
7
8
9
tab1 = { key1 = "val1", key2 = "val2", "val3" }
for k, v in pairs(tab1) do
print(k .. " - " .. v)
end
tab1.key1 = nil
for k, v in pairs(tab1) do
print(k .. " - " .. v) --不会打印key1了
end

bool类型

  • boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是”假”,其他的都为”真”:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    print(type(true))
    print(type(false))
    print(type(nil))
    if false or nil then
    print("至少有一个是 true")
    else
    print("false 和 nil 都为 false!") --false 和 nil 都为 false!
    end

number

  • Lua 默认只有一种 number 类型 – double(双精度)类型(默认类型可以修改 luaconf.h 里的定义),
    1
    2
    3
    4
    5
    6
    print(type(2))
    print(type(2.2))
    print(type(0.2))
    print(type(2e+1))
    print(type(0.2e-1))
    print(type(7.8263692594256e-06))

string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
string1 = "this is string1"
--[[可以输出换行的string]]
html = [[
<html>
<head></head>
<body>
<a href="http://www.w3cschool.cc/">w3cschool菜鸟教程</a>
</body>
</html>
]]
print(html)
--算数操作Lua尝试转换为number进行操作
print("1"+2) --3.0
--字符串连接用..
print("1".."2") --12
--符号#可计算字符串长度
print(#html)

table(表)

  • 在 Lua 里,table (类似于map,将list与map结合起来)的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表 index由1开始
local tbl2 = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl2) do
print("Key", key, val)
end
a = {}
a["key"] = "value" --保存一个键值对 "key":"value"
key = 10
a[key] = 22 --10:22
a[key] = a[key] + 11
for k, v in pairs(a) do --两个键值对
print(k .. " : " .. v)
end
  • table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。
    1
    2
    3
    4
    5
    6
    7
    a3 = {}
    for i = 1, 10 do
    a3[i] = i
    end
    a3["key"] = "val"
    print(a3["key"]) --val
    print(a3["none"]) --nil

function(函数)

1
2
3
4
5
6
7
8
9
10
11
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))

*function 可以以匿名函数(anonymous function)的方式通过参数传递:

1
2
3
4
5
6
7
8
9
function anonymous(tab, fun)
for k, v in pairs(tab) do
print(fun(k, v))
end
end
tab = { key1 = "val1", key2 = "val2" }
anonymous(tab, function(key, val)
return key .. " = " .. val
end)

thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

userdata(自定义类型)

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

循环

while

1
2
3
4
5
6
a=10
while( a < 20 )
do
print("a 的值为:", a)
a = a+1
end

for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
for var=exp1,exp2,exp3 do
<执行体>
end
--var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1。
--eg.
for i=1,f(x) do --此处的f(x)只会在初始化循环时候执行一次
print(i)
end
for i=10,1,-1 do
print(i)
end
--f(x)的例子
function f(x)
print("function")
return x*2
end
for i=1,f(5) do print(i)
end
--[[
function
1
2
3
4
5
6
7
8
9
10
--]]

泛型for循环

1
2
3
4
5
6
--打印数组a的所有值
a = {"Lua", "Tutorial"}
for i,v in ipairs(a)
do print(i..v)
end
--i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组。

repeat…until(类似do while)

1
2
3
4
5
6
7
--[ 变量定义 --]
a = 10
--[ 执行循环 --]
repeat
print("a的值为:", a)
a = a + 1
until( a > 15 )

不同循环可以嵌套

1
2
3
4
5
6
7
8
9
10
11
12
j =2
for i=2,10 do
for j=2,(i/j) , 2 do
if(not(i%j))
then
break
end
if(j > (i/j))then
print("i 的值为:",i)
end
end
end

break

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--[ 定义变量 --]
a = 10
--[ while 循环 --]
while( a < 20 )
do
print("a 的值为:", a)
a=a+1
if( a > 15)
then
--[ 使用 break 语句终止循环 --]
break
end
end

流程控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
--[ 定义变量 --]
a = 100
--[ 检查布尔条件 --]
if( a == 10 )
then
--[ 如果条件为 true 打印以下信息 --]
print("a 的值为 10" )
else if( a == 20 )
then
--[ if else if 条件为 true 时打印以下信息 --]
print("a 的值为 20" )
else if( a == 30 )
then
--[ if else if condition 条件为 true 时打印以下信息 --]
print("a 的值为 30" )
else
--[ 以上条件语句没有一个为 true 时打印以下信息 --]
print("没有匹配 a 的值" )
end
print("a 的真实值为: ", a )

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--实例
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))

函数作为参数

1
2
3
4
5
6
7
8
9
10
11
12
myprint = function(param)
print("这是打印函数 - ##",param,"##")
end
function add(num1,num2,functionPrint)
result = num1 + num2
-- 调用传递的函数参数
functionPrint(result)
end
myprint(10)
-- myprint 函数作为参数传递
add(2,5,myprint)

多返回值

1
s, e = string.find("w3cschool菜鸟教程:www.w3cschool.cc", "菜鸟教程") print(s,e)
1
2
3
4
5
6
7
8
9
10
11
12
13
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}))

可变参数

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

运算符

算数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 )
--[[
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
--]]

关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
a = 21
b = 10
if( a == b )
then
print("Line 1 - a 等于 b" )
else
print("Line 1 - a 不等于 b" )
end
if( a ~= b )
then
print("Line 2 - a 不等于 b" )
else
print("Line 2 - a 等于 b" )
end
if ( a < b )
then
print("Line 3 - a 小于 b" )
else
print("Line 3 - a 大于等于 b" )
end
if ( a > b )
then
print("Line 4 - a 大于 b" )
else
print("Line 5 - a 小于等于 b" )
end
-- 修改 a 和 b 的值
a = 5
b = 20
if ( a <= b )
then
print("Line 5 - a 小于等于 b" )
end
if ( b >= a )
then
print("Line 6 - b 大于等于 a" )
end

逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
print("---------分割线---------" )
-- 修改 a 和 b 的值
a = false
b = true
if ( a and b )
then
print("a and b - 条件为 true" )
else
print("a and b - 条件为 false" )
end
if ( not( a and b) )
then
print("not( a and b) - 条件为 true" )
else
print("not( a and b) - 条件为 false" )
end

特殊

1
2
3
4
5
6
7
8
9
10
a = "Hello "
b = "World"
print("连接字符串 a 和 b ", a..b )
print("b 字符串长度 ",#b )
print("字符串 Test 长度 ",#"Test" )
print("w3cschool菜鸟教程网址长度 ",#"www.w3cschool.cc" )

字符串

示例

1
2
3
4
5
6
7
string1 = "Lua"
print("\"字符串 1 是\"",string1)
string2 = 'w3cschool.cc'
print("字符串 2 是",string2)
string3 = [["Lua 教程"]]
print("字符串 3 是",string3)

字符串常用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
--转大写
print(string.upper("abc"))
--转小写
print(string.upper("ABC"))
--替换字符串 数字表示替换次数,忽略则全部替换
print(string.gsub("abcabc",'c','d',1))
--字符串查找 数字为起始位置,找到则返回起止位置
print(string.find("abcabc",'a',3))
--字符串反转
print(string.reverse("12345"))
--格式化字符串
string.format("the value is:%d",4)
--数字转换为字符串并连接
print(string.char(97,98,99,100))
--byte转换为整数,可指定位置,默认为1
print(string.byte("abc",2))
--计算长度 同#"string"
print(string.len("abc")==#"abc")
--返回字符串的n个拷贝
print(string.rep('a', 3))
--连接字符串
print("aaa"..'bbb')

数组

一维

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
array = {"Lua", "Tutorial"}
--Lua 索引值是以 1 为起始,但你也可以指定 0 开始。
for i= 0, 2 do
print(array[i])
end
--也可以用负数作为索引
array = {}
for i= -2, 2 do
array[i] = i *2
end
for i = -2,2 do
print(array[i])
end

多维

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 初始化数组
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
4
5
6
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end

自定义的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,4,0
do
print(i,n)
end

利用闭包实现的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end

Lua table

  • table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数字、字典等。
  • Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
  • Lua table 是不固定大小的,你可以根据自己需要进行扩容。
  • Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用”format”来索引table string。

初始化与销毁

1
2
3
4
5
6
7
8
9
-- 初始化表
mytable = {}
-- 指定值
mytable[1]= "Lua"
-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存

table的引用(类似Java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- 简单的 table 演示table类型的引用类似Java
mytable = {}
print("mytable 的类型是 ",type(mytable))
mytable[1]= "Lua"
mytable["wow"] = "修改前"
print("mytable 索引为 1 的元素是 ", mytable[1])
print("mytable 索引为 wow 的元素是 ", mytable["wow"])
-- alternatetable和mytable的是指同一个 table
alternatetable = mytable
print("alternatetable 索引为 1 的元素是 ", alternatetable[1])
print("mytable 索引为 wow 的元素是 ", alternatetable["wow"])
alternatetable["wow"] = "修改后"
print("mytable 索引为 wow 的元素是 ", mytable["wow"])
-- 释放变量
alternatetable = nil
print("alternatetable 是 ", alternatetable)
-- mytable 仍然可以访问
print("mytable 索引为 wow 的元素是 ", mytable["wow"])
mytable = nil
print("mytable 是 ", mytable)

table操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
--连接table中的所有元素,利用分隔符
t1={"a","b","c"}
print(table.concat(t1))
print(table.concat(t1,"@@"))
print(table.concat(t1,"@@",1,2))
--插入元素
table.insert(t1,"d")
print(t1[4])
table.insert(t1,2,"b")
print(t1[2])
--删除元素
print("当前元素:"..table.concat(t1,","))
table.remove(t1)
print("remove(t1)默认删除最后一个元素,当前元素:"..table.concat(t1,","))
table.remove(t1,1)
print("remove(t1,1)之后"..table.concat(t1,","))
--排序
t1={"c","b","a"}
print("排序前:"..table.concat(t1,","))
table.sort(t1)
print("排序后:"..table.concat(t1,","))

!!!慎用”#table”

  • 不要赋值nil,删除元素请使用remove
  • 元素不是同一类型length无明确意义
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    tbl = {"a", "b","c"}
    print("tbl 长度 ", #tbl) --3
    tbl = {"a", "b","c"="bb"}
    print("tbl 长度 ", #tbl) --2
    tbl = {"a", "b",nil}
    print("tbl 长度 ", #tbl) --2
    tbl = {"a", nil,"b",nil} --1
    print("tbl 长度 ", #tbl)

模块与包

自定义包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
-- 定义一个常量
module.constant = "这是一个常量"
-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end
local function func2()
print("这是一个私有函数!")
end
function module.func3()
func2()
end
return module
1
2
3
4
5
6
7
8
9
10
11
12
--使用自定义包
require("module")
print(module.constant)
module.func3()
--设置别名
local m = require("module")
print(m.constant)
m.func3()

加载策略

  • require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量LUA_PATH的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
    1
    2
    #LUA_PATH
    export LUA_PATH="~/lua/?.lua;;"

元表

  • 元表就是在table上加上自定义的对表数据的操作

    __index

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    --__index元方法查看表中元素是否存在,如果不存在,返回结果为nil;如果存在则由__index 返回结果。
    mytable = setmetatable({key1 = "value1"}, {
    __index = function(mytable, key)
    if key == "key2" then
    return "metatablevalue"
    else
    return mytable[key]
    end
    end
    })
    print(mytable.key1,mytable.key2)

__newindex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--当你给表的一个缺少的索引赋值,解释器就会查找__newindex元方法:如果存在则调用这个函数而不进行赋值操作。
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
mytable = setmetatable({key1 = "value1"}, {
__newindex = function(mytable, key, value)
rawset(mytable, key, "\""..value.."\"")
end
})
--使用rawset 函数来更新表
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)

__add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
--为表添加操作符
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- 两表相加操作(合并)
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
for i = 1, table_maxn(newtable) do
table.insert(mytable, table_maxn(mytable)+1,newtable[i])
end
return mytable
end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print("index:"..k,v)
end
--[[
__add 对应的运算符 '+'.
__sub 对应的运算符 '-'.
__mul 对应的运算符 '*'.
__div 对应的运算符 '/'.
__mod 对应的运算符 '%'.
__unm 对应的运算符 '-'.
__concat 对应的运算符 '..'.
__eq 对应的运算符 '=='.
__lt 对应的运算符 '<'.
__le 对应的运算符 '<='.
--]]

__call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
--__call元方法
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- 定义元方法__call
mytable = setmetatable({10}, {
__call = function(mytable, newtable)
sum = 0
for i = 1, table_maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1, table_maxn(newtable) do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {10,20,30}
print(mytable(newtable))

__tostring

1
2
3
4
5
6
7
8
9
10
11
--__tostring 元方法用于修改表的输出行为
mytable = setmetatable({ 10, 20, 30 }, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "表所有元素的和为 " .. sum
end
})
print(mytable)

协同(coroutine)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
--协程
-- coroutine_test.lua 文件
--create创建一个协程,未调用之前为阻塞状态
--此时co是协程对象
co = coroutine.create(
function(i)
print(i);
end
)
print(coroutine.status(co)) -- suspended
--与create配合使用唤醒协程进行传参
coroutine.resume(co, 1) -- 1
print(coroutine.status(co)) -- dead
print("----------")
--wrap返回一个函数a,调用a()则进入协程并传递参数
--此时co表示一个函数
co = coroutine.wrap(
function(i)
print(i);
end
)
co(1)
print("----------")
co2 = coroutine.create(
function()
for i=1,10 do
print(i)
if i == 3 then
print(coroutine.status(co2)) --running
print(coroutine.running()) --返回正在运行的线程号 thread:XXXXXX
end
coroutine.yield()--挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果
end
end
)
coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3
print(coroutine.status(co2)) -- suspended
print(coroutine.running())
print("----------")

resume与create的配合 注意resume与yield的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function foo (a)
print("foo 函数输出", a)
return coroutine.yield(2 * a) -- 返回 2*a 的值
end
co = coroutine.create(function (a , b)
print("第一次协同程序执行输出", a, b) -- co-body 1 10
local 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, 4
--第二次唤醒协同程序,参数传递给上一次的yield() line:3
print("main", coroutine.resume(co, "r")) -- true 11 -9
--第三次唤醒协同程序,参数传递给上一次的yield() line:11
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine

生产者-消费者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
local newProductor
function productor()
local i = 0
while true do
i = i + 1
send(i) -- 将生产的物品发送给消费者
end
end
function consumer()
while true do
local i = receive() -- 从生产者那里得到物品
print(i)
end
end
function receive()
local status, value = coroutine.resume(newProductor)
return value
end
function send(x)
coroutine.yield(x) -- x表示需要发送的值,值返回以后,就挂起该协同程序
end
-- 启动程序
newProductor = coroutine.create(productor)
consumer()

IO

简单模式(类c语言)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
--lua文件IO简单模式 类似c语言
--[[
file = io.open (filename [, mode])
r 以只读方式打开文件,该文件必须存在。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
r+ 以可读写方式打开文件,该文件必须存在。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a+ 与a类似,但此文件可读可写
b 二进制模式,如果文件是二进制文件,可以加上b
+ 号表示对文件既可以读也可以写
--]]
--
-- 以只读方式打开文件
file = io.open("test.txt", "r")
-- 设置默认输入文件为 test.lua
io.input(file)
-- 读取一个数字
print(io.read("*n"))
-- 读取n个字符
print(io.read(2))
-- 输出文件下一行 默认可不写,当前位置读取至换行止
print(io.read("*l"))
-- 从当前位置读取整个文件
print(io.read("*a"))
-- 关闭打开的文件
io.close(file)
-- 以附加的方式打开只写文件
file = io.open("test.lua", "a")
-- 设置默认输出文件为 test.lua
io.output(file)
-- 在文件最后一行添加 Lua 注释
io.write("-- test.lua 文件末尾注释")
-- 关闭打开的文件
io.close(file)

其他的IO函数

  • io.tmpfile():返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除
  • io.type(file): 检测obj是否一个可用的文件句柄
  • io.flush(): 向文件写入缓冲中的所有数据
  • io.lines(optional file name):返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,但不关闭文件

完全模式 IO.xxx变为file.xxx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 以只读方式打开文件
file = io.open("test.lua", "r")
-- 输出文件第一行
print(file:read())
-- 关闭打开的文件
file:close()
-- 以附加的方式打开只写文件
file = io.open("test.lua", "a")
-- 在文件最后一行添加 Lua 注释
file:write("--test")
-- 关闭打开的文件
file:close()
  • file:seek(optional whence, optional offset) 设置和获取当前文件位置
  • file:flush(): 向文件写入缓冲中的所有数据
  • io.lines(optional file name)打开指定的文件filename为读模式并返回一个迭代函数,每次调用将获得文件中的一行内容,当到文件尾时,将返回nil,并自动关闭文件。
    1
    2
    3
    4
    5
    6
    7
    8
    -- 以只读方式打开文件
    file = io.open("test.lua", "r")
    -- 从倒数25位置开始读取整个文件内容
    file:seek("end",-25)
    print(file:read("*a"))
    -- 关闭打开的文件
    file:close()
1
2
3
4
5
for line in io.lines("test.lua") do
print(line)
end

错误处理

assert与error

1
2
3
4
5
6
7
8
9
10
11
12
13
local function add(a,b)
assert(type(a) == "number", "a is not a number")
assert(type(b) == "number", "b is not a number")
if(a==b) then
-- error终止正在执行的函数,返回message,第二个参数为0,1,2
-- 表示0:不添加错误位置信息;1(默认):调用error位置(文件+行号)
-- 2:指出哪个调用error的函数的函数
error("err",2)
end
return a+b
end
print(add(10,20))

pcall与xpcall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
--pcall表示保护模式运行程序,第一个参数为函数,第二个参数为函数的参数
pcall(function(i) print(i) end, aa==1)
--无错误返回true,有错误返回false,err_info
has_err,err_info=pcall(function(i) print(i) error('error..') end, 33)
print(has_err,err_info)
--xpcall提供更详细的信息
function myfunction ()
n = n/nil
end
function myerrorhandler( err )
print( "ERROR:", err )
end
status = xpcall( myfunction, myerrorhandler )
print( status)

垃圾回收 lua为自动垃圾回收

  • collectgarbage(“collect”): 做一次完整的垃圾收集循环。通过参数 opt 它提供了一组不同的功能:
  • collectgarbage(“count”): 以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。
  • collectgarbage(“restart”): 重启垃圾收集器的自动运行。
  • collectgarbage(“setpause”): 将 arg 设为收集器的 间歇率 (参见 §2.5)。 返回 间歇率 的前一个值。
  • collectgarbage(“setstepmul”): 返回 步进倍率 的前一个值。
  • collectgarbage(“step”): 单步运行垃圾收集器。 步长”大小”由 arg 控制。 传入 0 时,收集器步进(不可分割的)一步。 传入非 0 值, 收集器收集相当于 Lua 分配这些多(K 字节)内存的工作。 如果收集器结束一个循环将返回 true 。
  • collectgarbage(“stop”): 停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。

面向对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 面向对象,使用table模拟实现
-- Meta class
Shape = {area = 0}
-- 基础类方法 new
function Shape:new (o,side)
o = o or {}
-- self类似this
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- 基础类方法 printArea
function Shape:printArea ()
print("面积为 ",self.area)
end
-- 创建对象
myshape = Shape:new(nil,10)
myshape:printArea()

继承与方法重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
-- Meta class
Shape = {area = 0}
-- 基础类方法 new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- 基础类方法 printArea
function Shape:printArea ()
print("面积为 ",self.area)
end
-- 创建对象
myshape = Shape:new(nil,10)
myshape:printArea()
Square = Shape:new()
-- 派生类方法 new
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
-- 派生类方法 printArea 重写
function Square:printArea ()
print("正方形面积为 ",self.area)
end
-- 创建对象
mysquare = Square:new(nil,10)
mysquare:printArea()
Rectangle = Shape:new()
-- 派生类方法 new
function Rectangle:new (o,length,breadth)
o = o or Shape:new(o)
setmetatable(o, self)
self.__index = self
self.area = length * breadth
return o
end
-- 派生类方法 printArea
function Rectangle:printArea ()
print("矩形面积为 ",self.area)
end
-- 创建对象
myrectangle = Rectangle:new(nil,10,20)
myrectangle:printArea()
文章目录
  1. Lua 应用场景
  2. Hello world!
  3. 注释
  4. 变量
    1. 全局变量
    2. 局部变量
    3. 赋值
    4. 索引
  5. 数据类型
    1. nil
    2. bool类型
    3. number
    4. string
    5. table(表)
    6. function(函数)
    7. thread(线程)
    8. userdata(自定义类型)
  6. 循环
    1. while
    2. for
    3. 泛型for循环
    4. repeat…until(类似do while)
    5. 不同循环可以嵌套
    6. break
  7. 流程控制
  8. 函数
    1. 函数作为参数
    2. 多返回值
    3. 可变参数
  9. 运算符
    1. 算数
    2. 关系
    3. 逻辑
    4. 特殊
  10. 字符串
    1. 示例
    2. 字符串常用操作
  11. 数组
    1. 一维
    2. 多维
  12. 迭代器
    1. 内置简单迭代
    2. 自定义的迭代器
    3. 利用闭包实现的迭代器
  13. Lua table
    1. 初始化与销毁
    2. table的引用(类似Java)
    3. table操作
    4. !!!慎用”#table”
  14. 模块与包
    1. 自定义包
    2. 加载策略
  15. 元表
    1. __index
    2. __newindex
    3. __add
    4. __call
    5. __tostring
  16. 协同(coroutine)
    1. resume与create的配合 注意resume与yield的参数传递
    2. 生产者-消费者
  17. IO
    1. 简单模式(类c语言)
      1. 其他的IO函数
    2. 完全模式 IO.xxx变为file.xxx
  18. 错误处理
    1. assert与error
    2. pcall与xpcall
  19. 垃圾回收 lua为自动垃圾回收
  20. 面向对象
    1. 继承与方法重写