一、Lua基础
1.1 变量类型
nil(空)、boolean、number(数字-不区分数字类型)、string、function、table、userdata(自定义)、thread(线程)
1.2 特点
动态类型、弱类型、大小写敏感、默认全局、带GC
二、运算符
2.1 数学运算
5 + 3 = 8
5 - 3 = 2
5 * 3 = 15
5 // 3 = 1
5 / 3 = 1.6666666666667
5 % 3 = 2
5.5 % 3 = 2.5
5 ^ 3 = 125.0
不存在:++ += =+
2.2 关系运算
< > >= <= == ~=
2.3 逻辑运算
and(&&):逐个判断,遇到false返回
or(||) :逐个判断,遇到true返回
not(!)
-注意:
a、false与nil 为false
b、没有三目运算符(? : )
--模拟三目运算
function JudgeAge(age)
return age > 18 and "adult" or "child"
end
result = JudgeAge(20) print(result)--adult
result = JudgeAge(15) print(result)--child
c、and优先级大于or
d、除…和^为右结合优先,其余为左结合优先
2.4 位运算
a = 3 --0000 0011
b = 5 --0000 0101
result = a&b print(result) -- a&b = 1
result = a|b print(result) -- a|b = 7
result = ~b print(result) -- ~b = -6
result = a<<2 print(result) -- a<<2 = 12
result = b>>1 print(result) -- b>>1 = 2
-注意:
lua5.1使用位运算,需引入第三方库,如bitlib
lua5.2使用位运算,使用内置库bit32
lua5.3使用位运算,可直接使用运算符
2.5 其它
2.5.1#
解释:相当于Length或Count
a、
s= "test"
result = #s
print(result)--4
b、
1)
nums = {1,nil,3,nil,4}
result = #nums
print(result )--5
2)
nums = {1,nil,3,nil,4,nil}
result = #nums
print(result )--3
3)
nums = {1,nil,3,nil,4,nil,x=100,y=200}
result = #nums
print(result )--3
注意:
#返回的个数,不包含Table中自定义键的键对数。
当最后一个默认键对的值为nil时,不统计所有键值为nil的键对数。
2.5.2 . .
解释:连接字符串
function Concat(a,b)
return a..b
end
result = Concat("str","ing")
print(result)--string
-注意:性能消耗大
三、数据结构-Table
3.1 说明
Lua唯一数据结构,下标从1开始,以键值对的方式存储(nil不能作为键)
3.2 举例
定义:
table = {1,"a",x = 100,y = 200,x = 300,2,table1 = {["x"] = 101, 2}}
table.z = 50
table[7] = 7
使用:
print(table[1])--1
print(table[2])--a
print(table["x"])--300
print(table.y)--200
print(table[3])--2
print(table["z"])--50
print(table[7])--7
print(table.table1.x)--101
print(table.table1[1])--2
print(table[10])--nil
print(table.table1["z"])--nil
3.3 遍历方式
3.3.1 pairs
for k,v in pairs(table) do
print(k,":",v)
end
输出结果:
1 : 1
2 : a
3 : 2
y : 200
z : 50
table1 : table: 0x21d76d0
7 : 7
x : 300
3.3.2 ipairs
for k,v in ipairs(table) do
print(k,":",v)
end
输出结果:
1 : 1
2 : a
3 : 2
-注意:
a、定义:table = {1,2,3,4,5}
table[7] = 7
for k,v in ipairs(table) do
print(k,":",v)
end
输出结果:
1 : 1
2 : 2
3 : 3
4 : 4
5 : 5
b、定义:table = {1,2,3,4,5,6}
table[7] = 7
for k,v in ipairs(table) do
print(k,":",v)
end
输出结果:
1 : 1
2 : 2
3 : 3
4 : 4
5 : 5
6 : 6
7 : 7
四、语句
4.1 添加注释
单行:–
多行:–[[ ]]
嵌套:[=[ ]=]
4.2 赋值
单变量:a = 100
多变量:a,b = 100,“string”
交换: a,b = b,a
4.3 分支
num = 100
if num > 100 then
print("more")
elseif num > 50 then
print("middle")
else
print("less")
end
4.4 循环
a、for循环
从1开始,100结束,每次+2,
for i = 1,100,2 do
print("i = ",i)
end
b、while循环
当i<10
i = 0
while i < 10 do
i = i + 1
if a>= 8 do
break
end
end
c、repeat循环
i=0,i+2,直到i>=10
i = 0
repeat
i = i + 2
until i>=10
Lua没有关键字:continue
五、函数
5.1 定义方式
a、基础写法
add = function(a,b)
return a+b
end
result = add(1,2)
print(result)--3
b、语法糖写法
function add(a,b)
return a+b
end
result = add(1,2)
print(result)--3
-注意:
传入:
1)定义两个参数,传入三个参数,不报错,第三个直接丢弃
2)定义三个参数,传入两个参数,若不使用未传参的参数不报错
传出:
1)返回三个返回值,接收两个返回值,不报错,第三个直接丢弃
2)返回两个返回值,接收三个返回值,不报错,接收到的第三个为nil
5.2 多返回值
function fun(a,b)
return a+b,a*b
end
sum,product = fun(1,2)
print(sum)--3
print(product)--2
5.3 高阶函数
解释:Lua中的函数,可作为参数传递
function add(a,b)
return a + b
end
function fun(f,a,b)
return f(a,b)
end
result = fun(add,1,2)
print(result)--3
5.4 可变参数
解释:当参数个数不确定时,用…代替
function add(...)
local sum = 0
local arg = {...}
for k,v in ipairs(arg) do
sum = sum +v
end
return sum
end
result = add(1,2,3,4)
print(result)--10
六、函数库
6.1 引用方式
a、基础写法
str = "string"
result = string.upper(str)
print(result)--STRING
b、语法糖写法-不适用于多参数
str = "string"
result1 = str : upper()
print(result1)--STRING
result2 = str.upper(str)
print(result2)--STRING
6.2 函数库浏览
七、协程
7.1 create示例
1)
co = coroutine.create(
function()
print("start")--(1)
coroutine.yield()
print("after yield")--(3)
end
)
coroutine.resume(co)
print("yield")--(2)
coroutine.resume(co)
输出:
(1)start
(2)yield
(3)after yield
2)
co = coroutine.create(
function(num1,num2)
print("First num1 =",num1," num2 =",num2)--(1)
temp1,temp2 = coroutine.yield("startCor",1)
print("Second num1 =",num1," num2 =",num2)--(3)
print("Second temp1 =",temp1," temp2 =",temp2)--(4)
end
)
result1,result2,result3 = coroutine.resume(co,100,101)
print(result1, result2, result3)--(2)
coroutine.resume(co,200,201)
输出:
(1)First num1 = 100 num2 = 101
(2)true startCor 1
(3)Second num1 = 100 num2 = 101
(4)Second temp1 = 200 temp2 = 201
7.2 wrap示例
1)
fun = coroutine.wrap(
function()
print("start")--(1)
coroutine.yield()
print("after yield")--(3)
end
)
fun()
print("yield")--(2)
fun()
输出:
(1)start
(2)yield
(3)after yield
2)
fun= coroutine.wrap(
function(num1,num2)
print("First num1 =",num1," num2 =",num2)--(1)
temp1,temp2 = coroutine.yield("startCor",1)
print("Second num1 =",num1," num2 =",num2)--(3)
print("Second temp1 =",temp1," temp2 =",temp2)--(4)
end
)
result1,result2 = fun(100,101)
print(result1, result2)--(2)
fun(200,201)
输出:
(1)First num1 = 100 num2 = 101
(2)startCor 1
(3)Second num1 = 100 num2 = 101
(4)Second temp1 = 200 temp2 = 201
7.3 create与wrap
定义:
co = coroutine.create()
fun = coroutine.wrap()
不同点:
1)返回类型不同。
create()返回类型为thread。
wrap()返回类型为function。
2)执行方式不同。
create依靠coroutine.resume(co)。
wrap依靠fun()。
3)默认返回不同。
coroutine.resume()默认返回bool-即是否成功执行。
fun()默认返回nil。
4)调用Dead不同。
coroutine.resume()调用处于dead状态的协程无效果。
fun()调用处于dead状态的协程报错。
相同点:
1)每次调用coroutine.resume(co)或fun(),执行协程一部分代码,即可调用次数与coroutine.yield数量有关。
2)
每次调用coroutine.resume(co)或fun()传入的参数,作为coroutine.yield的传出参数返回。
每个coroutine.yield的传入参数作为对应coroutine.resume(co)或fun()的传出参数返回。
仅第一次调用coroutine.resume(co)或fun()传入的参数,作为create()或wrap()的传入参数。
-注意:
Lua中的协程可以无coroutine.yield
协程生命周期:start-suspend-running-dead-end
说明:通过coroutine.resume(co)或fun(),使状态由suspend转为running,之后可通过coroutine.yield转回suspend
八、元表与元方法
8.1 元表
(1)lua中的每个值都可以有一个元表,只是table和userdata可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表。
(2)lua代码中只能设置table的元表,至于其他类型值的元表只能通过C代码设置。
(3)多个table可以共享一个通用的元表,但是每个table只能拥有一个元表。
(4)我们称元表中的键为事件(event),称值为元方法(metamethod)。
(5)可通过函数getmetatable查询任何值的元表。
(6)可通过函数setmetatable替换表的元表
详细解释
8.2 元方法
8.2.1 __index
定义: 索引 table[key]。 当 table 不是表或是表 table 中不存在 key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。
尽管名字取成这样, 这个事件的元方法其实可以是一个函数也可以是一张表。
解释:
__index用于查询键对应的值。
1)首先判断table中的是否存在想要查询的键,如果存在则返回
2)如果不存在或table不是表,则判断table是否存在元表
3)如果存在元表,则判断元表中是否有__index方法
4)如果存在__index方法,则调用该方法。
--如果该方法是函数则调用该函数,并将table作为第一个参数。
--如果该方法是表,则将该表作为初始table,从第一步开始判断。
(1)如果__index方法是一个函数,则以 table 和 key 作为参数调用它
table = {a = 1}
metatable = {
__index = function(table,key)
return 123
end
}
print(table["b"])---nil
setmetatable(table,metatable)
print(table["b"])---123
(2)如果__index方法是一张表,最终的结果就是以 key 取索引这张表的结果。 (这个索引过程是走常规的流程,而不是直接索引, 所以这次索引有可能引发另一次元方法。)
table = {a = 1}
metatable = {
__index = {
b = 2
}
}
print(table["b"])---nil
print(table["c"])---nil
setmetatable(table,metatable)
print(table["b"])---2
print(table["c"])---nil
8.2.2 __newindex
定义:索引赋值 table[key] = value 。 和索引事件类似,它发生在 table 不是表或是表 table 中不存在 key 这个键的时候。 此时,会读出 table 相应的元方法。
同索引过程那样, 这个事件的元方法即可以是函数,也可以是一张表。 一旦有了 “newindex” 元方法, Lua 就不再做最初的赋值操作。 (如果有必要,在元方法内部可以调用 rawset 来做赋值。)
解释:
__newindex用于对键赋值。
1)首先判断table中的是否存在想要查询的键,如果存在则重新赋值该键
2)如果不存在或table不是表,则判断table是否存在元表
3)如果存在元表,则判断元表是否存在__newindex方法
4)如果存在__newindex方法,则调用该方法。
--如果该方法是函数则调用该函数,并将table作为第一个参数传入。
--如果该方法是表,则将该表作为初始table,从第一步开始判断。
5)如果table不存在元表或元表不存在__newindex方法,且table是表,则在当前表新增键值对。
(1)如果是一个函数, 则以 table、 key、以及 value 为参数传入。
table = {a = 1}
metatable = {
__newindex = function(table,key,value)
end
}
print(table["b"])---nil
print(table["c"])---nil
table["b"] = 2
setmetatable(table,metatable)
table["c"] = 3
print(table["b"])---2
print(table["c"])---nil
table = {a = 1}
metatable = {
__newindex = function(table,key,value)
--table[key] = value --stack overflow 死循环
--t["c"]=3 -> mt.__newindex () -> table[key]=value -> mt.__newindex () -> table[key]=value -> ...
rawset(table,key,value)
end
}
print(table["b"])---nil
print(table["c"])---nil
table["b"] = 2
setmetatable(table,metatable)
table["c"] = 3
print(table["b"])---2
print(table["c"])---3
(2) 如果是一张表, Lua 对这张表做索引赋值操作。 (这个索引过程是走常规的流程,而不是直接索引赋值, 所以这次索引赋值有可能引发另一次元方法。)
local k = {}
local metatable = {
__newindex = k
}
local table = {}
setmetatable(table, metatable)
print("赋值前:")--赋值前:
for k,v in pairs(k) do
print(k ,v)--无输出
end
table[1] = 20
print("赋值后:table表中的值:")--赋值后:table表中的值:
for k,v in pairs(table) do
print(k ,v)--无输出
end
print("赋值后:k表中的值:")--赋值后:k表中的值:
for k,v in pairs(k) do
print(k ,v)--1 20
end
8.2.3 __call
定义:函数调用操作 func(args)。 当 Lua 尝试调用一个非函数的值的时候会触发这个事件 (即 func 不是一个函数)。 查找 func 的元方法, 如果找得到,就调用这个元方法, func 作为第一个参数传入,原来调用的参数(args)后依次排在后面。
解释:
当把非函数table当做函数使用时,
先判断table是否存在对应元表,
如果存在则判断元表中是否存在__call方法,
如果存在__call方法,且该方法是函数则调用该方法,
并将table当做第一个参数传入,其余参数依次排在后面。
function fun(table,x,y)
return table.n+x+y
end
table = {}
table.n = 100
metatable = {}
metatable.__call = fun
setmetatable(table,metatable)
print(table(1,2))--103
九、面向对象(Object Oriented)
9.1 模拟对象
1)初始版本
local monster = {
name = "Monster1",
HP = 100,
pos = {x=100,y=200}
}
monster.TakeDamage = function(self,damage)
self.HP = self.HP - damage
end
monster.TakeDamage(monster,10)
result = monster.HP
print(result)--90
2)语法糖版本
local monster = {
name = "Monster1",
HP = 100,
pos = {x=100,y=200}
}
function monster:TakeDamage(damage)
self.HP = self.HP - damage
end
monster:TakeDamage(10)
result = monster.HP
print(result)--90
3)合并版本
local monster = {
name = "Monster1",
HP = 100,
pos = {x=100,y=200},
TakeDamage = function(self,damage)
self.HP = self.HP - damage
end
}
monster:TakeDamage(10)
result = monster.HP
print(result)--90
9.2 模拟类
1)初始版本
CMonster = {
name="Monster",
HP=100,
TakeDamage = function(self,damage)
self.HP = self.HP - damage
end,
ShowInfo = function(self)
print(self.Name,self.HP)
end
}
function CMonster:new(name,hp,x,y)
local obj = {}
obj.Name = name
obj.HP = hp
obj.X = x
obj.Y = y
setmetatable(obj, {__index = CMonster})
return obj
end
local obj1 = CMonster:new("Monster1",100,100,101)
obj1:ShowInfo()--Monster1 100
obj1:TakeDamage(20)
obj1:ShowInfo()--Monster1 80
2)优化版本
CMonster = {
name="Monster",
HP=100,
TakeDamage = function(self,damage)
self.HP = self.HP - damage
end,
ShowInfo = function(self)
print(self.Name,self.HP)
end
}
CMonster.__index = CMonster
function CMonster:new(name,hp,x,y)
local obj = {}
obj.Name = name
obj.HP = hp
obj.X = x
obj.Y = y
setmetatable(obj, CMonster)
return obj
end
setmetatable(CMonster,{__call = function(self,name,hp,x,y)
return self:new(name,hp,x,y)
end
})
local obj1 = CMonster("Monster1",100,100,101)
obj1:ShowInfo()--Monster1 100
obj1:TakeDamage(20)
obj1:ShowInfo()--Monster1 80
9.3 模拟继承
说明:8.2脚本文件名为Monster.lua
local monster = require("Monster")--继承Monster.lua
local MagicMonster = {
MP =200,
Attack = function(self,consume)
self.MP = self.Mp - consume
end
}
setmetatable(MagicMonster,{
__index = monster,
__call = function(self,name,hp)
local obj = CM(name,hp)
setmetatable(obj,{__index = MagicMonster})
return obj
end
})
local magicMonster1 = MagicMonster("MagicMonster1 ",100)
magicMonster1 :ShowInfo()--MagicMonster1 100
magicMonster1 :TakeDamage(20)
magicMonster1 :ShowInfo()--MagicMonster1 80
9.4 模拟多态
说明:8.2脚本文件名为Monster.lua
local monster = require("Monster")--继承Monster.lua
local MagicMonster = {
MP =200,
Attack = function(self,consume)
self.MP = self.Mp - consume
end
}
setmetatable(MagicMonster,{
__index = monster,
__call = function(self,name,hp)
local obj = CM(name,hp)
setmetatable(obj,{__index = MagicMonster})
return obj
end
})
local magicMonster1 = MagicMonster("MagicMonster1 ",100)
magicMonster1 :ShowInfo()--MagicMonster1 100
function MagicMonster:ShowInfo()
print("Magic Monster:", self.name, self.HP)
end
magicMonster1 :ShowInfo()--Magic Monster: MagicMonster1 80
9.5 模拟私有成员
1)直接封装
function GetMonster()
local self = {HP = 123, Name = "monster"}
local function GetHP()
return self.HP
end
local function GetName()
return self.Name
end
local function TakeDamage(_,count)
self.HP = self.HP - count
if self.HP <= 0 then
self.HP = 0
end
end
return {GetHP = GetHP, TakeDamage = TakeDamage, GetName = GetName}
end
local monster = GetMonster()
print(monster:GetHP())--123
monster:TakeDamage(20)
print(monster:GetHP())--103
monster.HP = 100
print(monster:GetHP())--103
2)元表封装
local Monster = {}
Monster.HP = 100
Monster.Type = "Monster"
function Monster:GetHP()
return self.HP
end
function Monster:TakeDamage(damage)
self.HP = self.HP - damage
end
function Monster:SetHP(hp)
self.HP = hp
end
function Monster.new()
local obj = {HP = Monster.HP}
setmetatable(obj, Monster)
Monster.__index = {GetHP = Monster.GetHP, TakeDamage = Monster.TakeDamage}
Monster.__newindex = function(table,key,value)
if key == "Type" then
print("Forbiden operate.")
return
end
rawset(table,key,value)
end
return obj
end
return Monster
local monster = require("Monster")
local obj = monster:new()
print(obj:GetHP())--100
obj:TakeDamage(10)
print(obj:GetHP())--90
--obj:SetHP(200) --报错 该方法为私有方法,不可访问
print(obj.Type)--Monster
obj.Type = "Monster Test"--Forbiden operate.
print(obj.Type)--Monster
print(obj.MP)--nil
obj.MP = 100
print(obj.MP)--100
十、闭包
function counter()
local i = 0
return function()
i = i + 1
return i
end
end
local c1 = counter()
print(c1())--1
print(c1())--2
print(c1())--3
local c2 = counter()
print(c2())--1
print(c2())--2
print(c2())--3
定义:通过调用含有一个内部函数加上该外部函数持有的外部局部变量(upvalue)的外部函数(就是工厂)产生的一个实例函数
闭包详解
十一、关键字
11.1 local
lua中变量默认为全局变量,加local进行限制,转变为局部变量。