lua学习

因为Moongen的需要,学习了一些Lua知识,特此总结。

现在更新到lua的模块与包。

注释

字符串匹配模式以后补充。

包的加载机制和C包以后补充。

installation

1
brew install lua

注:lua的index都是从1开始的。

Lua数据类型

  • nil
  • boolean
  • number
  • string
  • function
  • userdata
  • thread
  • table

nil

nil表示值无效,对于全局变量和table,nil还有删除的作用,赋值为nil之后即删除了这个值

注:不能说type(X) == nil,而要说type(X) == "nil",因为type(type(X)) == string

boolean

分为truefalse,而且nil的值也为false

number

lua默认只有一种number类型:double。(默认类型可以在luacof.h中修改)

string

字符串类型。

[[]]用来表示一整块字符。

..用来连接字符串。

在对一个数字字符串上进行算术操作时,Lua会尝试将这个数字字符串转成一个数字。

使用#来计算字符串,比如

1
2
> print(#"www")
3

table

table的创建通过构造表达式来完成。

1
2
3
4
5
6
-- 创建一个空表
local tbl1 = {}

-- 创建初始化表
local tbl2 = {"a", "b"}
tbl = {"alpha", "beta", [3] = "uno", ["two"] = "dos"}

table实际上是一个关联数组(就是一个map),初始化的表通过index可以访问,但是index从1开始。

遍历一张表

1
2
3
for key, val in pairs(t) do
print (key .. " : " .. val)
end

赋值或访问

1
2
3
print(tbl1[1])
tbl1["key"] = "value"
tbl1[1] = 1

function

lua中函数被看成第一类值。

函数可以被存在变量里,即

1
2
3
4
5
6
7
8
9
10
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还可以通过匿名函数的方式传递

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

Lua变量

Lua有三种变量,全局变量、局部变量、表中的域

直接声明即为全局变量。

局部变量通过local声明。局部变量的作用范围为包围他的语句块。

1
2
3
4
5
6
7
8
a = 5               -- 全局变量
local b = 5 -- 局部变量

function joke()
c = 5 -- 全局变量
local d = 6 -- 局部变量
end
-- 局部变量d变为nil

赋值语句

直接赋值=

可以对多个变量同时赋值,如a, b = c, d。赋值的时候Lua会先计算右边所有的值,再赋值,这样可以直接用同时赋值的方法交换变量。

  • 变量个数>值的个数的时候,按变量个数补nil。

  • 变量个数<值的个数的时候,忽略多余变量。

多个值赋值常常用来交换变量,或者获得函数返回值,如a, b = f()

Lua循环

分为while、for、repeat三种。并支持break。

1
2
3
4
5
6
7
8
9
10
11
12
13
while (condition)
do
statements
end

-- var为变量名,exp1为var起始,exp2为var结束,exp3为步长,如exp3不指定则为1,两端为闭区间
for var = exp1, exp2, exp3 do
statements
end

repeat
statements
until(condition)

泛型for循环

通过一个迭代器函数来遍历所有值。

1
2
3
4
5
--打印数组a的所有值  
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end

其中ipairs为Lua提供的一个迭代器函数,用来迭代数组。

Lua流程控制

即if语句和嵌套。

1
2
3
4
5
6
7
8
9
if (布尔表达式)
then
statements
-- else
-- statements
-- elseif (布尔表达式)
-- then
-- statements
end

Lua函数

函数定义为

1
2
3
4
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语言函数可以返回多个值,每个值以逗号隔开。

多返回值

用逗号隔开

可变参数

在函数列表中使用...表示可变参数。

调用的时候可以通过table方式调用。(相当于传入一个map)

1
2
3
4
5
6
7
8
9
10
11
function average(...)
result = 0
local arg={...} --> 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))

也可以通过select("#",...)来获得可变参数的数量。

如果需要固定参数,在...前面加上好了,一样逗号隔开,但是必须放在可变参数之前。

可变参数单个访问可以用select(i, ...)访问第i个元素。

Lua运算符

算术运算符+-*/%^-

关系运算符==~=(不等于),><>=<=

逻辑运算符andornot

其他运算符..(连接两个字符串),#(返回字符或表的长度)

Lua字符串

字符串可以用如下三种方法表示

  • 单引号间的一串字符。
  • 双引号间的一串字符。
  • [[和]]间的一串字符。

字符串操作

注:下面的string为保留字

  • string.upper():转成大写字母

  • string.lower():转成小写字母

  • string.gsub(mainString, findString, replaceString[, num]):在字符串中将mainString中的findString全部用replaceString替换num次,无num则全部替换。

  • string.find(str, substr, [init[, end]]):从init到end在str中寻找substr

  • string.reverse(str):翻转

  • string.format(…):像printf一样

  • string.char(arg)和string.byte(arg[, int]):在char和int之间转换。byte函数的int用来指定第几个字符,默认第一个。char函数可以有多个参数,返回连在一起的字符串。

  • string.len(arg):字符串长度

  • string.rep(string, n):重复string n次。

  • ..:连接字符串

  • string.gmatch(str, pattern):返回一个迭代器函数。每一次调用函数返回下一个符合pattern描述的子串

    1
    for word in string.gmatch("Hello Lua user", "%a+") do print(word) end
  • string.match(str, pattern[, init]):返回第一个匹配出的子串(?这个好像解释不对,没有试过)

string.format

  • %c - 接受一个数字, 并将其转化为ASCII码表中对应的字符
  • %d, %i - 接受一个数字并将其转化为有符号的整数格式
  • %o - 接受一个数字并将其转化为八进制数格式
  • %u - 接受一个数字并将其转化为无符号整数格式
  • %x - 接受一个数字并将其转化为十六进制数格式, 使用小写字母
  • %X - 接受一个数字并将其转化为十六进制数格式, 使用大写字母
  • %e - 接受一个数字并将其转化为科学记数法格式, 使用小写字母e
  • %E - 接受一个数字并将其转化为科学记数法格式, 使用大写字母E
  • %f - 接受一个数字并将其转化为浮点数格式
  • %g(%G) - 接受一个数字并将其转化为%e(%E, 对应%G)及%f中较短的一种格式
  • %q - 接受一个字符串并将其转化为可安全被Lua编译器读入的格式
  • %s - 接受一个字符串并按照给定的参数格式化该字符串

匹配模式

因为现在不用,暂时就不放了,相关连接

http://www.runoob.com/lua/lua-strings.html

Lua数组

一维数组很简单a = {}

多维数组也很简单

1
2
3
4
5
6
7
array = {}
for i=1,3 do
array[i] = {}
for j=1,3 do
array[i][j] = i*j
end
end

Lua迭代器

ipairs和pairs的区别

pairs会返回所有key和value,而ipairs会从index为1开始,遇到value为nil就停止。

无状态的迭代器和多状态的迭代器

for泛型的调用过程

在这之前,有必要讲一下for泛型的调用过程。

对于一个for泛型所需要的迭代器内容,共有三个值:迭代函数、状态常量、控制变量。执行过程如下:

  • 首先,初始化,计算in后面表达式的值,表达式应该返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
  • 第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于for结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
  • 第三,将迭代函数返回的值赋给变量列表。
  • 第四,如果返回的第一个值为nil循环结束,否则执行循环体。
  • 第五,回到第二步再次调用迭代函数

无状态的迭代器

无状态的迭代器指不保留任何状态,每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用。典型例子是ipairs。以下是一个例子

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,3,0
do
print(i,n)
end

多状态的迭代器

很多情况下,迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法是将所有的状态信息封装到table中,将table作为迭代器的状态常量。以下是一个遍历table的迭代器。

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操作

注:下面的table为保留字

  • table.concat(table[, sep[, start[, end]]]):将table从start到end的所有东西用sep(分隔符)隔开并连接在一起
  • table.insert(table[, pos], value):在table数组部分pos位置插入值为value的元素
  • table.maxn(table):指定table中所有正数key值中最大的key,如果不存在key值为正数的返回0.(在Lua5.2之后不存在了)
  • table.remove(table[, pos]):返回table数组位于pos的元素,后面的元素会前移。
  • table.sort(table[, comp]):对给定的table进行升序排序。

Lua模块与包

模块类似与一个封装库,Lua的模块是由变量、函数等已知元素组成的table,因此创建一个模块就是创建一个table,将需要导出的常量和函数放入其中,最后返回这个table就行了。

模块示例

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

require函数

使用require("模块名")或者require"模块名"来加载模块。如果直接使用require的话,lua会定义与这个模块名相同的全局变量。如下:

1
2
3
require("module")
print(module.constant)
module.func3()

也可以给它赋值m = require("模块"),此时m就是一个别名变量。

加载机制

以后补充。

C包

以后补充。

Lua原表

Lua协同程序

Lua文件I/O

Lua错误处理

Lua调试

Lua垃圾回收

Lua面向对象

Lua数据库访问

参考资料