循环
|
for
|
数值for循环, 语法:
for var=exp1,exp2,exp3 do
<执行体>
end
exp3是可选的,如果不指定,默认为1
|
举例:
for i = 0, #ret, 1
do
print("process: "..ret[i]["name"])
end
I 表示初始变量
#ret 表示表的长度
1表示每循环一次 I 的值增加多少,可以是负数
|
泛型for循环,语法:
for k, v in ipairs/pairs(a)
do
<执行体>
end
|
举例:
for k, v in pairs(ret)
do
print(k, v)
end
ret是一个表
|
|
while
|
语法:
while(condition)
do
statements
end
condition 可以括号也可以不用括号
|
举例:
i = 0
while true
do
if i > #ret then
break
end
print(i)
i = i + 1
end
|
i = 0
while i < #ret
do
print(i)
i = i + 1
end
|
|
repeat
|
语法:
repeat
statements
until ( condition )
condition 可以括号也可以不用括号
|
举例:
i = 0
repeat
print(ret[i]["name"])
i = i + 1
until (i > #ret)
|
代码块
|
do end
|
关键字for 后面必须带do end
|
关键字while后面必须带 do end
|
then end
|
关键字if后面执行的代码需要用then end包起来
|
function
end
|
关键字function定义的函数,结束要用end标识
|
条件语句
|
If语句
|
if(布尔表达式) –括号可以不要
then
--[ 在布尔表达式为 true 时执行的语句 --]
end
|
|
if...else
|
if(布尔表达式)
then
--[ 布尔表达式为 true 时执行该语句块 --]
else
--[ 布尔表达式为 false 时执行该语句块 --]
end
|
函数
|
function
|
Lua函数可以返回多个值
|
Lua函数支持变参,然后通过for 来迭代访问参数
function print_arg(...)
local args = {...}
for _, v in ipairs(args)
do
print(v)
end
end
print_arg(1, 2, "hello", "world")
|
函数调用必须带括号, 除了单个参数的函数, 并且参数类型为字符串, 表构造器时, 可以不带括号
|
Lua可以返回函数
function print_arg(...)
local args = {...}
for _, v in ipairs(args)
do
print(v)
end
end
function return_function()
return print_arg
end
_xxxprint_arg = return_function()
_xxxprint_arg("hello", "sysnap")
|
|
字符串
|
string
|
string库中所有的字符索引从前往后是1,2,...;从后往前是-1,-2,...
|
string库中所有的function都不会直接操作字符串,而是返回一个结果
|
string.byte(str, pos)可以把指定的位置的字符转为 ASCII 编码
string.char(asc1, ...) 可以把ASCII 编码转为字符,比如string.char(104, 104)
|
在lua5.1,同时也作为string类型的成员方法,既可以写成string.upper(s), 也可以s:upper()
|
|
查找
|
string.find(s, pattern, [pos])
第1个参数:源字符串
第2个参数:待搜索之模式串
第3个参数:A hint, 从pos位置开始搜索,可以不写,默认是1
找到匹配返回:匹配串开始和结束的位置,否则返回nil,举例
pos = 1;
while true
do
s1, s2 = teststr:find("123", pos)
if(s1 == nil) then
break;
end
print("find str pos: ", s1, s2)
pos = s1 + 1;
end
|
|
模式
|
字符,大写表示补集,比如%W表示不是字母也不是数字
|
.
|
任意字符
|
%s
|
空白串
|
%p
|
标点,比如!,。?;
|
%c
|
控制字符,比如回车,换行符
|
%d
|
数字
|
%x
|
十六进制数字
|
%z
|
代表0的字符
|
%a
|
字母
|
%l
|
小写字母
|
%u
|
大写字母
|
%w
|
字母或者数字
|
字符集
|
[]
|
[%[%]]'匹配一对方括号。
[01] 匹配二进制数字。
[0-9a-fA-F] 匹配 16进制数,跟%x作用是一样的。
[0-7] 表示 [01234567]。
|
修饰符
|
+
|
匹配前一字符一次或多次
|
*
|
匹配前一字符0次或多次,最长匹配
|
-
|
匹配前一字符0次或多次,最短匹配.[ ] 里面-的意义见上面
|
?
|
匹配前一字符0次或1次
|
^
|
匹配字符串开头,如果放在[]里面,表示NOT意思
|
$
|
匹配字符串结尾
|
转义字符
|
%
|
'%' 用作特殊字符的转义字符
'%.' 匹配点;
'%%' 匹配字符 '%'。
转义字符 '%'不仅可以用来转义特殊字符,还可以用于所有的非字母的字符
|
捕获: 在模式中,用小括号括起来的子模式,它在匹配发生的时候截取小括号内模式匹配到的字符串,然后保存下来,默认最多保存 32 个,可以理解是sscanf, 括起来的模式串只是告诉LUA这个串匹配到的内容要存起来并返回
|
举例:
pair = "name = Anna"
_, _, key, value = string.find(pair, "(%a+)%s*=%s*(%a+)")
print(key, value) --> name Anna
date = "17/7/1990"
_, _, d, m, y = string.find(date, "(%d+)/(%d+)/(%d+)")
print(d, m, y) --> 17 7 1990
s = "then he said: \"its all right\"!"
a, b, quotedPart = string.find(s, "([\"].-[\"])")
print(quotedPart) --> "its all right"
一个空的捕获,也就是小括号里面什么内容也没有,它会返回当前字符串的比较操作进行到的位置
s = "then he said: \"it's all right\"!"
a, b, q = string.find(s, "()([\"].-[\"])")
print(q) --> 15
%后面接数字 1-9 表示用前面模式捕获的序号 1-9 对应的字符串来替换模式匹配的内容
local s = "am+dmf"
print(string.gsub(s, "()(m+)", "%1")) -- a2+d5f 2
--匹配到m的时候,位置是2,所以第一个捕获()输出是2,这时%1表示第一个捕获的值,这里是2,这里把m改---为2,接着继续匹配,匹配到dmf这个m的时候,位置是5,这时%1的值是5
\command{some text}将它们转换为XML风格的字符串:<command>some text</command>
s = string.gsub(s, "\\(%a+){(.-)}", "<%1>%2</%1>")
|
举例
s = "Deadline is 30/05/1999, firm"
date = "%d%d/%d%d/%d%d%d%d"
print(string.sub(s, string.find(s, date))) --> 30/05/1999
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
print(w) –可以理解为匹配到一次之后,继续再匹配
--string.match就只匹配一起
end
string.gsub("hello, up-down!", "%A", ".") 表示把任何非字母的字符替换为点号.
*和-长匹配短匹配的差别
test = "int x; /* x */ int y; /* y */"
print(string.gsub(test, "/%*.*%*/", "<COMMENT>"))
输出--> int x; <COMMENT>
然而模式 '.-' 进行的是最短匹配,她会匹配 "/*" 开始到第一个 "*/" 之前的部分:
test = "int x; /* x */ int y; /* y */"
print(string.gsub(test, "/%*.-%*/", "<COMMENT>"))
输出--> int x; <COMMENT> int y; <COMMENT>
|
闭包
|
|
先看一个例子
function bibao()
local var = 0
function _subfunc()
var = var + 1
print("var: "..var)
return var
end
return _subfunc
end
f = bibao()
f()
f()
输出是1, 2
function bibao(var)
--local var = 0
function _subfunc()
var = var + 1
print("var: "..var)
return var
end
return _subfunc
end
f = bibao(2)
f()
f()
输出是3,4
这里变量var对于_subfunc而言,既不是全局变量,也不是局部变量,但又能被访问到,这个变量叫upvalue,upvalue实际指的是变量而不是值,这些变量可以在内部函数之间共享
定义: 闭包是一个函数加上它可以正确访问的 upvalues,这个函数一般是一个匿名函数,并且定义在另一个函数内部;这个函数可以访问定义在外部函数内的成员变量,参数,以及全局函数
闭包应用场景:
1 作为函数的参数,比如gsub第三个参数可以指定一个function
2 创建一个函数,即函数返回一个函数
3 函数hook,比如io.open这个替换为我们的函数,保存老的函数做一些文件权限的检查
4 实现迭代器,每个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置及如何进到下一个位置。闭包刚好适合这种场景
|
迭代器
|
|
利用闭包实现的一个简单迭代器
function iter(t)
local pos = 0
local maxn = table.getn(t)
function get_item()
pos = pos + 1
if(pos <= maxn) then
return t[pos]
end
return nil
end
return get_item
end
t = { "1sysnap", "2jim", "3green"}
for k,_ in iter(t)
do
print(k)
end
local it = iter(t)
local item = nil
while true
do
item = it()
if(item == nil) then
break
end
print(item)
end
|
元表
|
|
背景:
改变table的行为,每个行为关联了对应的元方法。比如俩个表相加
当Lua试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫"__add"的字段,若找到,则调用对应的值。"__add"等即时字段,其对应的值(往往是一个函数或是table)就是"元方法"
|
__index元方法例子:
t = { ["name"] = "sysnap"}
print(t["name"])
也可以写为t = { name = "sysnap"}
print(t.name)
再看一个元表的例子
t = { name = "sysnap", ["foo"] = 2}
mt = {}
mt.__index = t
newt = setmetatable({}, mt )
--newt = setmetatable({}, {__index = t})
print(newt.name, newt["foo"])
Lua查找一个表元素时的规则,其实就是如下3个步骤:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续。
3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值。
t = { name = "sysnap", ["foo"] = 2}
function newd(tb, key)
print("key: ", key)
return t[key]
end
mt = {}
mt.__index = newd
newt = setmetatable({}, mt )
print(newt.name, newt["foo"])
|
__tostring元方法例子: 控制表的输出
function printTable(t, n)
if "table" ~= type(t) then
return 0;
end
n = n or 0;
local str_space = "";
local str_return = "";
for i = 1, n do
str_space = str_space.." ";
end
str_return = (str_space.."{\n");
for k, v in pairs(t) do
local str_k_v = str_space.." ["..tostring(k).."] = ";
if "table" == type(v) then
str_return = str_return..str_k_v.."\n";
printTable(v, n + 1);
else
str_k_v = str_k_v..tostring(v);
str_return = str_return..str_k_v.."\n";
end
end
str_return = str_return..str_space.."}";
return str_return
end
tb = { name = "sysnap", ["foo"] = 2}
setmetatable(tb, {__tostring = printTable})
print(tb)
|
__call元方法: 类似C++的仿函数
t = { name = "sysnap", ["foo"] = 2}
t.__call = function (self, arg1) –因为是.访问,第一个参数是表本身,如果没传递参数这--里都可以直接为空
print("hello table!"..arg1)
end
setmetatable(t, t)
print(t(1))
|
面向对象
|
|
.调用函数: 句号要显示传递或接收self参数
tb = { data1 = "hello", data2 = "world"}
function tb.hello(self)
print("hello world"..self.data1)
end
tb.hello(tb)
|
:调用函数: 冒号默认传自己为参数,通过self关键字访问
tb = { data1 = "hello", data2 = "world"}
function tb:hello() –这里如果不用:是没办法用self关键字的
print("hello world"..self.data1)
end
tb:hello()
|
|
|
|
|
模块
|
|
Lua 5.1提供了一个新函数module,囊括了上面一系列定义环境的功能。在开始编写一个模块时,可以直接用module("modname", package.seeall)来取代前面的设置代码。在一个模块文件开头有这句调用后,后续所有代码都不需要限定模块名和外部名字,同样也不需要返回模块table
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
请发表评论