目录
概述
虽然已经很多年没有使用过Lua了,但是在司内的知识分享中,又捡了起来。这里总结了自己之前使用过程中遇到的一些奇怪的问题,以及重要或者奇怪的使用方法。
而且不同版本的Lua,表现形式都不同。这里推荐在练习时使用zerobrane studio,可以很方便地切换Lua的版本。
关于多行注释的安全问题
如果直接使用默认的–[[和–]]来进行多行注释的时候,如果遇到table包table的情况会直接结束注释:
--[[
a = [];
b = [a];
a[b[1]]
a = 1
--]]
可以使用另一种方法来进行多行注释,避免这个问题:
--[=[
a = [];
b = [a];
a[b[1]]
a = 1
]=]
当然,最安全的方法还是使用IDE的快捷键进行注释。IDE会在每行的前面加单行注释,避免错误的发生。
多行字符串安全问题
多行字符串,也会出现类似于上面的情况:
str =
[[
话说
这个东西
好像打印不出来
就是这个
table[table[idx]]
咋办啊
]]
print(str)
运算符相关
#运算符
#运算符取的是最大索引的值,如果删除了部分中间的值,获得的结果不会改变:
tb_a = {1, 2, 3}
print (#tb_a)
tb_a[2] = nil
print (#tb_a)
但是这种情况仅限于Lua 5.1 ,Lua5.3和Lua5.4结果是1。
and or
模拟三目运算符的and…or…,在第二个参数为false时,始终返回c,会出现问题:
a = true
print (a and false or true)
输出结果会是true 而不是三目运算符应该返回的false。
这时候,可以将三目运算符的后面两个部分转换成table,运算结束后再取第一个元素,即可实现:
a = true
b = (a and {false} or {true})[1]
if b then
print("true")
else
print("false")
end
迭代器相关
自定义迭代器
for 变量列表 in 迭代函数, 状态变量, 控制变量 do
-- 循环体
end
自定义无状态迭代器
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,因此只需要一个参数即可:
array = {"Google", "Csdn"}
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
循环时的goto语句
可以使用goto语句来实现continue:
for i=1, 3 do
if i <= 2 then
print(i, "yes continue")
goto continue
end
print(i, " no continue")
::continue::
print([[i'm end]])
end
元表
Lua可以通过设置元表,定义元方法的方式,改变table的一些行为:
index
index元方法,可以修改按索引取值的逻辑。
若index内容是一个表的话,如果table里没有值,会从元表中对应的索引去取:
t_table = setmetatable({k1 = "v1"}, {__index = {k2 = "v2"}})
print(t_table["k1"])
print(t_table["k2"])
t_table["k2"] = "v3"
print(t_table["k2"])
--[[
输出是:
v1
v2
v3
--]]
若__index内容是一个函数,则可以定义返回逻辑:
t_table = setmetatable({}, {__index =
function(t_table, key)
if key == 1 then
return "true"
else
return "false"
end
end
})
print(t_table[1])
print(t_table[2])
print(t_table[3])
t_table = {1, 2, 3}
print(t_table[1])
print(t_table[2])
print(t_table[3])
--[[
输出是:
true
false
false
1
2
3
--]]
__newindex
__newindex元方法,可以修改追加索引时的逻辑
t_table = setmetatable({k1 = "v1"}, {
__newindex =
function(t_table, key, value)
rawset(t_table, key, "\"v" .. value .. "\"")
end
})
t_table["k2"] = 2
print(t_table["k1"])
print(t_table["k2"])
--[[
输出是:
v1
"v2"
--]]
add和tostring
t_table = setmetatable({1, 2, 3}, {__add =
function(t_table, data)
t_table[#t_table + 1] = data
return t_table
end,
__tostring =
function(t_table)
local res = ""
for _, v in pairs(t_table) do
res = res .. v
end
return res
end
})
print(t_table)
print(t_table + 4)
--[[
输出:
123
1234
--]]
其它运算符对应原表
元表 | 运算符 |
---|---|
add | + |
sub | - |
mul | * |
div | / |
mod | % |
unm | -(相反数) |
concat | … |
eq | == |
lt | < |
le | <= |
注意事项
需要注意的是,关系运算符,比较的两端,元表必须相同。如果只有一方有元表,另一方没有,又或者是两方拥有不同的元表,会导致比较报错:
a_metatable =
{
__gt = function(a_table, b_table)
return a_table[1] > b_table[1]
end,
__lt = function(a_table, b_table)
return a_table[1] < b_table[1]
end
}
b_metatable =
{
__gt = function(a_table, b_table)
return b_table[1] > a_table[1]
end,
__lt = function(a_table, b_table)
return b_table[1] < a_table[1]
end
}
a_table = setmetatable({0}, a_metatable)
b_table = setmetatable({1}, b_metatable)
print(a_table<b_table)
--[[
报错内容是:
attempt to compare two table values
--]]
取反的重写
a_metatable =
{
__unm = function(a_table)
local _temp_table = {}
for i = #a_table, 1, -1 do
_temp_table[#a_table + 1 - i] = a_table[i]
end
return _temp_table
end
}
p_metatable =
{
__tostring =
function(a_table)
local res = ""
for _, v in pairs(a_table) do
res = res .. v
end
return res
end
}
a_table = setmetatable({1, 2, 3}, a_metatable)
b_table = setmetatable(-a_table, p_metatable)
print(b_table)
__call
function_content =
{
__call = function(a_table, a_data)
print(a_data)
end
}
func_print = setmetatable({}, function_content)
b = func_print(4)
协程的实现
function sleep(n)
local t0 = os.clock()
while os.clock() - t0 <= n do end
end
-- 这里的sleep会占用大量资源 正常逻辑不能使用
test_coroutine = coroutine.create(
function()
for i = 1, 10, 1 do
print(i)
sleep(0.1)
coroutine.yield()
end
end
)
function do_cro(co)
while(coroutine.status(co) ~="dead") do
coroutine.resume(co)
end
end
do_cro(test_coroutine)
面向对象的table实现
用table实现了类与继承:
-- 类
-- 类管理器
CClassManager = {}
function CClassManager.ctor(cls, ...)
local this = {}
setmetatable(this, cls)
cls.__index = cls -- 将元表的__index设为自身,访问表的属性不存在时会搜索元表
cls.init(this, ...)
return this
end
function CClassManager.VInit(self, ...)
end
function CClassManager.init(self, ...)
self:VInit(...)
end
function CClassManager.dtor(cls)
-- do sth
end
-- 通过继承实现的类的定义
ClassT = CClassManager:ctor()
function ClassT.VInit(self, word)
self.word = word
end
function ClassT.say(self)
print(self.word)
end
test = ClassT:ctor("B")
test:say()
test:dtor()
test:say()