LUA基础
循环 |
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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步