环境: Mac, Lua 5.3.4
- lua的常用数据类型:
nil, boolean, number, string, userdata, function, table, thread
- 在lua中
false,nil
为假,其他为真
在and
中,如果第一个操作数为假,则返回第一个操作数,比如:
4 and 5 -- 5
nil and 6 -- nil
false and true -- false
true and nil -- nil
{} and 1 -- 1
在or
中,如果第一个操作数为真, 则返回第一个操作数,比如:
true or false -- true
nil or false -- false
false or "hi" -- hi
0 or 5 -- 0
{} or nil -- table:...
- 使用
type
判定类型:
print(type(10), type(10.3)) -- number, number
print(type(nil)) -- nil
print(type(type)) -- function
print(type(type(nil))) -- string
print(type({})) -- table
-- 在字符串参与算术运算时,都会被当作浮点数处理
-- 原因在于Lua存储字符串使用8bit存储
print("10" + 1) -- 11.0
print("10" .. 1) -- 101
print(10 .. 1) -- 101
- 数值的表示是有长度限制的,标准Lua使用64bit来存储整型值,其最大值约等于10的19次方
print(math.mininteger) -- -9223372036854775808 最小
print(math.maxinteger) -- 9223372036854775807 最大
print(math.maxinteger + 1 == math.mininteger) -- true
print(math.mininteger - 1 == math.maxinteger) -- true
- 对于比较操作,不会对操作数像算术运算那样实行强制转换,如果比较中混用字符串和数字会抛出异常
-- Error: attempt to compare number with string
print(2 < "14")
- Lua语言中遍历的几种方式:
pairs
: 遍历元素的出现顺序可能是随机的,但是遍历中的每个元素仅会出现一次
ipairs
: 遍历元素按照顺序执行, 也就是索引+1, 直到遇到value为nil或者key+1没有的,就会暂停
-- 索引+1条件不符合
local tab = {"one", [3] = "three", [4] = "four"}
for i, v in ipairs(tab) do
print(i, v) -- 1 one
end
-- value 存在nil
local tab = {"one", [3] = nil , "two", [4] = "four"}
for i, v in ipairs(tab) do
print(i, v) -- 1 one, 2 two
end
-- 遍历顺序,比如table.nums,主要使用pairs
-- 也可能会使用:#, 但注意:table中不能包含nil
function table.nums(t)
local count = 0
for k, v in pairs(t) do
count = count + 1
end
return count
end
pairs的实现:
— 每次循环调用iter,a为状态变量,table,i为控制变量
function iter(a, i)
-- i的值在闭包中进行了累计,闭包的本质就是用于数据的存储计算
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function ipairs(a)
return tier, a, 0
end
- Lua语言中可使用可变长参数,使用
...
来表示,比如:
function Add(...)
local args = {...} -- 获取可变参数table
local result = 0
for i, v in pairs(args) do
result = result + v
end
return result
end
print(Add(1,2)) -- 3
print(Add(1,2,3)) -- 6
print(Add(1,2,3,4)) -- 10
- Lua语言中有个特性叫做
尾调用
。
它被当作函数调用使用的跳转,当一个函数的最后一个动作是调用另一个函数而没有进行其他工作时,就形成了为调用。
进行尾调用的时不会产生额外的栈空间,我们将这种实现称为尾调用消除。
不符合尾调用的方式有:
-- 该问题在于调用完g(x)后,f在返回前要丢弃g返回的结果
function f(x) g(x) end
-- 进行了加法
return g(x) + 1
-- 必须将返回值限制为1个
return x or g(x)
return (g(x))
尾调用的方式为:
-- 方式1
function foo(n)
if n > 0 then
return foo(n-1) end
end
end
-- 方式2,
return x[i].foo(x[j] + a*b, i + j)
只有返回形如 return func(args)
的才是尾调用
- 为了更好控制局部变量的生效,可使用
do ... end
方法
local a, b = 1, 2 -- 在文件中生效
do
local a1, b1 = 3, 4 -- 仅在do ... end 程序块中生效
print(a, b) -- 1 2
print(a1, b1) -- 3 4
end
print(a, b) -- 1 2
print(a1, b1) -- nil nil
- 尽可能的使用局部变量是一种良好的编程风格,它的优点:
-
避免不必要的的命名造成全局变量的混乱
-
避免同一程序中不同代码部分的命令冲突
-
会随作用域的结束而释放
-
访问局部变量比全局变量更快,因此编程中会将某些方法声明为局部,比如:
local RANDOM = math.random
local num = self:getNum()
- 在连接字符串的时候,通常使用
..
。
但是要注意下,关于读取较大文件内容时,会出现卡顿,比如:
-- 文件内容大小约为4.5M
local buff = ""
for line in io.lines() do
buff = buff .. line .. "\n"
end
--[[
假设每行有20个字节,当读取2500行内容后,buff大小约为50KB,当程序在使用
buff .. line .. "\n"连接字符串的时候,会创建约50000个字节
然后再将50Kb的内容拷贝到新字符串中
如此重复的操作,对于不可变的字符串会产生至少移动50G的数据
]]
-- 可使用table.concat连接
local _tab = {}
for line in io.lines() do
-- 将内容放置到表中
_tab[#_tab + 1] = line
end
local buff = table.concat(_tab, "\n")
- 闭包是为保存状态提供的一种良好机制。
闭包就是一个可以访问自身环境中一个或多个局部变量的函数,这些变量upvalue
将连续调用过程中的值保存在闭包中
ipairs的实现就是闭包。
function values(t)
local i = 0
return function()
i = i + 1
return t[i]
end
end
- 关于表的初始化
-- 初始化方式一:
local strTab = { x= "1", y = "2", z = "3"}
-- 初始化方式二:
local strTab = {}
strTab.x = "1"
strTab.y = "2"
-- 总结:方式一种能够提前判断表的大小,速度会更快
- 判定表是否为
nil
或者{}
,可使用接口:next
local tabB = {}
if tabB and next(tabB) then -- 推荐,注意在Lua中,只有false,nil为假
print("ok")
else
print("nil")
end
- 表删除元素的方式:
-- 不推荐
local tab = {2,3,2,3,2,3}
for _, value in pairs(tab) do
if value == 2 then
table.remove(tab, value)
end
end
print(table.concat(tab, ",")) -- 2,2,3
-- 推荐方式1: 从后往前删除
local tab = {2,3,2,3,2,3}
for i = #tab, 1, -1 do
if tab[i] == 2 then
table.remove(tab, i)
end
end
print(table.concat(tab, ",")) -- 3,3,3
-- 推荐方式2: 使用while
local tab = {2,3,2,3,2,3}
local i = 1
while i <= #tab do
if tab[i] == 2 then
table.remove(tab, i)
else
i = i +1
end
end
print(table.concat(tab, ",")) -- 3,3,3
- 元表主要用于对表进行操作,比如相加等
-- 创建新表时,默认不带元彪, 可使用:getmetatable
local _tab = {}
print(getmetatable(_tab)) -- nil
-- 设置元表,可使用:setmetatable
local _tab = {}
print(getmetatable(_tab)) -- nil
local _tab1 = {}
setmetatable(_tab, _tab1)
print(getmetatable(_tab) == _tab1) -- true
--[[
元表中有一些参数注意:
__index: 读取元表数据,如果普通表不存在,会根据__index继续查找字段或方法
__newIndex: 写入元表数据,元表存在时,会根据__newIndex写入数据
__metatable: 保护对象的元表metatable不被修改
__mode: 用于保证对象可以被回收,有key, value keyValue三种,尤其针对于table引用
]]
- require的特性:
--[[
特性:
1. 加载文件
2. 避免重复加载文件
]]
-- 如果我想重复加载文件,实现方式:
package.loaded["app/LoginScene"] = nil
require("app/LoginScene")
End