两年没有碰过Lua了,总觉得得要捡起来。现在从头到尾再过一遍,总结一些东西。之前根据菜鸟学的时候,使用了5.1.1的版本。与现在常用的版本相悖。因此这次我使用了:zerobrane studio,它可以方便切换版本,能实现很好的练习效果。
关于多行注释的安全问题
如果直接使用默认的–[[和–]]来进行多行注释的时候,如果遇到table包table的情况会直接结束注释:1
2
3
4
5
6--[[
a = [];
b = [a];
a[b[1]]
a = 1
--]]
可以使用另一种方法来进行多行注释,避免这个问题:1
2
3
4
5
6--[=[
a = [];
b = [a];
a[b[1]]
a = 1
]=]
当然,最安全的方法还是使用IDE的快捷键进行注释.IDE会在每行的前面加单行注释,避免错误的发生.
多行字符串安全问题
多行字符串,也会出现类似于上面的情况:1
2
3
4
5
6
7
8
9
10str =
[[
话说
这个东西
好像打印不出来
就是这个
table[table[idx]]
咋办啊
]]
print(str)
运算符相关
#运算符取的是最大索引的值,如果删除了中间的值,获得的结果不会改变:1
2
3
4
5tb_a = {1, 2, 3}
print (#tb_a)
tb_a[2] = nil
print (#tb_a)
但是这种情况仅限于Lua 5.1 ,Lua5.3和Lua5.4结果是1。
模拟三目运算符的and…or…,在第二个参数为false时,始终返回c,会出现问题:1
2a = true
print (a and false or true)
输出结果会是true 而不是三目运算符应该返回的false。
这时候,可以将三目运算符的后面两个部分转换成table,运算结束后再取第一个元素,即可实现:1
2
3
4
5
6
7a = true
b = (a and {false} or {true})[1]
if b then
print("true")
else
print("false")
end
自定义迭代器
自定义迭代器的格式:1
2
3for 变量列表 in 迭代函数, 状态变量, 控制变量 do
-- 循环体
end
自定义无状态迭代器1
2
3
4
5
6
7
8
9
10
11function 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,因此只需要一个参数即可:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18array = {"Google", "Runoob"}
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:1
2
3
4
5
6
7
8
9for 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内容是一个表的话,如果table里没有值,会从元表中对应的索引去取:1
2
3
4
5
6
7
8
9
10
11t_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内容是一个函数,则可以定义返回逻辑: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
28t_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元方法,可以修改追加索引时的逻辑1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17t_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|+|
|sub|-|
|mul|*|
|div|/|
|mod|%|
|unm|-(相反数)|
|concat|..|
|eq|==|
|lt|<|
|le|<=|
add和tostring:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21t_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
--]]
需要注意的是,关系运算符,比较的两端,元表必须相同。如果只有一方有元表,另一方没有,又或者是两方拥有不同的元表,会导致比较报错:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25a_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
--]]
重写取反操作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24a_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比较有意思,可以让table可以变得和函数一样可以执行。因此可以写成如下的极其过分的形式:1
2
3
4
5
6
7
8
9
10function_content =
{
__call = function(a_table, a_data)
print(a_data)
end
}
func_print = setmetatable({}, function_content)
b = func_print(4)
协程
1 | function sleep(n) |
面向对象
用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-- 类
-- 类管理器
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()