lua将Boolean值false和nil外的其他所有值始为真。
if not nil then
print("false") ---false
end
if not false then
print("false") --- false
end
if 0 then
print("true") ---true
end
and和or都遵循短路求值。and,第一个为假返回第一个操作时,否则返回第二个;or第一个为true返回第一个,否则返回第二个。所以可以使用如下赋值方式:
local a = b or {} --这样,当b为nil时,返回后面的{}赋值给a
-- 相当于
if not b then a = {} end
- 根据and运算优先于or,所以用and和or还可以实现类似于c#或Java中的三目运算。
--三元运算可以用下面的方式
local d = e and a or f --当e为真时,返回a和f进行or运算,若a为真,返回a,否则返回f;
--若e为假,永远返回f
- lua 5.3 引入整型,可以通过math.type进行区分。
print(math.type(3.0)) -- float
print(math.type(3)) -- Integer
在算数运算中,除法运算和幂运算,会将操作数全部转化为浮点型(不管操作数是浮点型还是整形),结果也是浮点型;其他运算若操作数有一个是浮点型,则会将另一个也转化为浮点型。
print(math.type(3.0 + 3)) -- float
print(math.type(3 + 3)) --Integer
print(math.type(3 / 3)) -- float
- floor运算符
//
相当于math.floor(),向负无穷取整;取模运算%
比较特殊,符号位永远与第二个操作数保持一致,例如a % b,b为正,无论a是正是负,结果永远为正。推导公式为 a%b = a - (a // b) * b
print(-3//2) -- -2
print(-3 % 2) -- 1 -3 - (-3 // 2) * 2 = -3 - (-4) = 1
print(3 % 2) -- 1 3 - (3 // 2) *2 = 3 - 2 = 1
- C# 的除法运算是向0取整,所以取余运算符%与第一个操作数的符号保持一致
Console.WriteLine(13 % -2); // -6
Console.WriteLine(13 / -2); // 1 13 - (-6) * (-2) = 1
C语言中float存储方式这里
- lua 浮点数表示范围,标准lua使用64为表示数值,其中一位为符号位,11个指数为,52个小数位;精简lua使用32为存储,一个符号位,8个指数位,23个小数位。
- 以精简lua为例,float存储格式为
1.b * 2 ^ c
,其中b为小数位,决定数据精度,在不考虑指数的情况下,23位尾数能表示的范围是[0,2 ^ 23 - 1],而用科学计数法表示,整数部分肯定为1,所以float能精确表示的范围有整数部分 + 尾数部分 = 23 + 1 = 24位,(上尾数位前面还隐含了一个"1"(小数点前面为非零数),所以应该是一共24位数字),所能表示的范围是[0, 2 ^ 24 -1]也就是说在这个范围内的整数是可以精确表示的,化为十位数大致为[0,16777215],也就是10 ^ 7
, - c为指数位置,决定范围,共有八位,为了表示负指数,所以存储为 c + 127,所以指数最大为 1111 1111,IEEE规定全为1表示无穷大(所以最大为1111 1110),全为0表示0(因为科学技术法表示,尾数小数点的左边一位为非零数,所以无论指数是多少,都不能为0,所以特殊表示),也就是共计2 ^ 253个数,[-126,127],其中-127表示0,128表示无穷大,所以最大为2 ^ 127,换算为10进制大约为10 ^ 38,所以范围大约为[-10 ^ 38 , 10 ^ 38]。
常用字符串format
- 输入两位数字,不够两位,前面补0
print(string.format("%02d",3))
- 保留3位小数字,不够补零
print(string.format("%0.3f",0.4))
```字符串长度为4,不足用空格补齐
``` lua
print(string.format("%4s"," 1"))
表基础
- 表的键可以用任何类型表示,但是tab[2] = 4,和 tab['2'] = 5表示两个不同的元素。
local tab = {[2] = 4,["2"] = 5}
print(tab['2'],tab[2]) -- 5 4
- 当被用作表的键值时,任何能够被转换为整型的浮点数都会被转换为整型数,不能转化的则不会发生上述转换。
local tab = {[2] = 4,["2"] = 5}
print(tab[2]) -- 4
tab[2.0] = 6
print(tab[2]) --6
- 使用表构造器构造表,运行幅度更快 (a = { k = 2,b = 4 }这种类型);表的某个元素值为nil时,会删除元素。
- ipairs和pairs的区别:ipairs只能遍历连续的数组,也就是按顺序排列的,1,2,3。否则会终止,但可以保证顺序;pairs则可以遍历所有元素,但遍历的顺序是随机的。
local tab = {[1] = 5,[3] = 3,["2"] = 5}
for k,v in ipairs(tab) do
print(k , " - ",v)
end
-- 输出:
-- 1 - 5
for k,v in pairs(tab) do
print(k , " - ",v)
end
-- 输出:没按顺序
-- 1 - 5
-- 2 - 5
-- 3 - 3
安全访问表的小技巧,例如要做一个连续判断:
if a and a.b and a.b.c and a.b.c.d then
-- body
end
--上面那种写法,很低效,做一次判断访问了6次表,可以写成如下形式
if (((a or {}).b or {}).c or {}).d then
-- body
end
--这种形式值访问了3次表,而且还短,相当于C#中的`?.`操作符
当函数有一个参数,且参数是字符串或表构造器时,可以省略函数的括号。
function t(a)
print(2)
end
t '3' --相当于t(3)
t{} -- 相当于t({})
- 函数被作为表达式(例如加法,减法的操作数)调用时,只返回第一个返回值。
function t(a)
return 2,4
end
print(t() + 3) -- 5
- 函数是一系列表达式中的最后一个表达式时,才会返回多个返回值,否则只能返回一个。
function t(a)
return 2,4
end
local x,y = t(),5
print(x,y) -- 2 5 ;4被丢弃
- 将函数用圆括号括起来,可以强制其返回一个返回值
function t(a)
return 2,4
end
print(t()) -- 2 4
print((t())) - 2
- 函数可以
...
代表可变长参数,代表可以有任意多个参数。可以用table.pack函数,将参数打包成一个表返回,这个表中还包含了额外的n
字段,存储了表的长度。例如
function t(...)
local args = table.pack(...)
for i = 1, args.n do
print(i,args[i])
end
end
print(t(3,4,6,7,2))
-- 1 3
-- 2 4
-- 3 6
-- 4 7
-- 5 2
- 也可以使用select遍历可变长参数,函数select总是具有一个固定的参数selector,如果selector是数字n,则select返回地n个参数后的
所有
参数;否则selector应该是#
,返回参数的总数。例如
function t(...)
for i = 1, select('#',...) do
print(i,(select(i,...))) --此处需要用括号括起来,以便只返回一个返回值
end
end
print(t(3,4,6,7,2))
-- 1 3
-- 2 4
-- 3 6
-- 4 7
-- 5 2
- 利用goto可以实现continue,goto需要跳转到标签位置,标签前后各跟两个冒号,例如::name::
function t(...)
for i = 1, select('#',...) do
if i < 3 then
goto continue
end
print(i,(select(i,...)))
::continue::
end
end
print(t(3,4,6,7,2))
-- 3 6
-- 4 7
-- 5 2
lua的两个移位操作都会用0填充空出的位置,也就是说符号位置也会移动,所以负数右移动会变为一个很大的整数,所以要谨慎使用。
错误检查函数
- erroe(message,level):函数抛出错误信息,通常包含调用堆栈信息以及错误提示信息,运行到此处会终止运行。其中message为自定义的出错信息;level为为可选的出错位置信息,默认为1,即为调用error函数的位置;2即为调用error函数的函数的位置;0则不打印出错位置信息!
function en()
if true then
error("444",0)
end
end
en()
-- 发生异常: main.lua:78: 444
-- stack traceback:
-- [C]: in function 'error'
-- main.lua:78: in main chunk
-- [C]: in ?
-- c:/Users/27238/.vscode/extensions/actboy168.lua-debug-1.22.5/runtime/
--win64/lua53/lua.exe: 444 --此处并没有指明出错位置
-- stack traceback:
-- [C]: in function 'error'
-- D:\Unity\workspace\lua/main.lua:79: in function 'en'
-- D:\Unity\workspace\lua/main.lua:82: in main chunk
-- [C]: in ?
function en()
if true then
error("444",1)
end
end
en()
-- c:/Users/27238/.vscode/extensions/actboy168.lua-debug-1.22.5/
-- runtime/win64/lua53/lua.exe: D:\Unity\workspace\lua/main.lua:79: 444 -- 79行为error的位置
-- stack traceback:
-- [C]: in function 'error'
-- D:\Unity\workspace\lua/main.lua:79: in function 'en'
-- D:\Unity\workspace\lua/main.lua:82: in main chunk
-- [C]: in ?
function en()
if true then
error("444",2)
end
end
en()
-- c:/Users/27238/.vscode/extensions/actboy168.lua-debug-1.22.5/runtime/win64/
-- ua53/lua.exe: D:\Unity\workspace\lua/main.lua:82: 444 --82为调用en的我位置
-- stack traceback:
-- [C]: in function 'error'
-- D:\Unity\workspace\lua/main.lua:79: in function 'en'
-- D:\Unity\workspace\lua/main.lua:82: in main chunk
-- [C]: in ?
- assert(v,message) ,会先检查第一个参数是否为真,若为真,则会返回该参数;否则会引发调用error函数,引发一个错误,并且会终止运行,第二个参数为错误信息。
local t = assert(3+4,"error")
print(t) -- 7
assert(nil,"can not nil")
-- c:/Users/27238/.vscode/extensions/actboy168.lua-debug-1.22.5/runtime/win64/lua53/
-- lua.exe: D:\Unity\workspace\lua/
-- main.lua:77: can not nil -- 指明了错误的位置,也打印出了自定义的message
-- stack traceback:
-- [C]: in function 'assert'
-- D:\Unity\workspace\lua/main.lua:77: in main chunk
-- [C]: in ?
- pcall(func,args),以一种保护模式调用其第一个参数,来捕获其错误。
无论错误是否发生,pcall都不会发生错误,即不会终止运行
。如果没有错误发生,pcall返回true和所有返回值;若有错,返回false和错误信息。第二个参数为目标函数的参数列表。
local success,msg = pcall(function(k,v)
return k + v
end,4,3)
print(success,msg) -- true 7
local success2,msg2 = pcall(function(k,v)
return k + v + nil
end,4,3)
print(success2,msg2)
-- false D:\Unity\workspace\lua/main.lua:72: attempt to perform arithmetic on a nil value
- xpcall (f, msgh,args),与pcall类似,可以额外添加一个错误处理函数。f为自定义函数,msgh为错误处理函数,args为自定义函数的参数列表。返回值与pcall一样,而且
无论错误是否发生,都不会终止运行
local success2,msg2 = xpcall(function(k,v)
return k + v + nil
end,debug.traceback,4,3)
print(success2,msg2)
-- false D:\Unity\workspace\lua/main.lua:72: attempt to perform arithmetic on a nil value
-- stack traceback:
-- D:\Unity\workspace\lua/main.lua:72: in function <D:\Unity\workspace\lua/main.lua:71>
-- [C]: in function 'xpcall'
-- D:\Unity\workspace\lua/main.lua:71: in main chunk
-- [C]: in ?
对比pcall和xpcall可以看出,错误信息多了stack traceback:以及其后面的内容。这是debug.traceback函数的作用,其可以使用调用栈来构造详细的错误信息,通俗的就是说可以告诉我们函数哪里出错了,以及哪里调用了该函数,以及调用函数的函数是哪里调用的,一次类推,直到最顶层位置。
建议用xpcall代替pcall的使用,更有利于我们找出错误位置
Lua Table实现
- Lua Table的存储非为两部分,一部分为数组,一部分为哈希散列表(类似于C#中的dictionary,也是由数组实现), 数组部分从1开始作整数数字索引。这可以提供紧凑且高效的随机访问。
而不能被储存在数组部分的数据全部放在哈希表中
,唯一不能做哈希键值的是nil,这个限制可以 帮助我们发现许多运行期错误。 - 详细的
- 详细2