Lua 学习之基础篇十<Lua 常见的语法规则>
下面讲一些lua 常见的用法和规则,可以为学习理解lua带来帮助,最后附上的部分是lua的基本操作,基本包含所有常用语法语句。
1. if判断
lua把 nil 和false 视为“假”,其他都为“真”
2. 逻辑运算符 and or
lua的and or 可以用来构成三元表达式,如下:
> = 1 == 1 and 1 or 2
1
但如果是这样写,就不是你想要的结果了:
> = 1 == 1 and false or true
true
这是因为,and 运算符判定 false不成立,就继续执行了 or 运算符的结果(nil和false lua都认为为假)
如果你一定要返回 true 或 false,要这么写:
> = ( 1 == 1 and {false} or {true} )[1]
false
3. local变量声明
local var1=1,var2
以上 ,var1和var2的作用域不同,var1是所在作用域的变量,var2可能是全局变量。实际上述命令解释后为 var1 取 "1,var2" 组成的值第一个值,类似 local var1 = ...
请注意变量的声明,如果不确定,就老老实实依依赋值。
local var1
local var2=1
print(var1) --nil
print(var2) --1
print("=====")
local var3 =1,var4
print(var3) --1
print(var4) --nil
print("=====")
local var5, var6=1
print(var5) --1 ->是不是很奇怪- -、这里的var5竟然是1
print(var6) --nil
4. table是否为空
if a == {} then
结果是false,这是一个逻辑错误,实际比较table a的内存地址和一个匿名table的是否相同
正确的写法是:
if next(a) == nil then
5. 多个变量赋值
name,name = 1,2
那name等于多少呢?
实际上name值为1,可以写个小例子 a,b = 2,3,4打印就可以看到了。a=2,b=3
6. table的key规则
t[name]与t["name"], t.name
第一种和后两种是不同的,第一种会根据取name的值做key,后两种以 "name"做key。这种情况还有:
t = {[name] = 1}
t = {name = 1}
t = {["name"] = 1}
7. table的长度
取得 table 长度最常用的做法是 #table,如下:
> t = {1,2,3}
> #t
3
但 # 操作符也是有局限的,不支援数组以外的对象计算,所以要谨记
> t = { 10, n = 20, 30, 40 }
> #t
3 --长度是4,所以,要采用其他方式判定长度
另外,通过把元素设 nil 无法改变 #table 的结果(除非是数组最后一个元素);而 table.remove 则可以立即更新 #table 的结果
t ={1,2,3}
t[1]=nil
print(#t) --3
table.remove(t,1)
print(#t) --2
8. table引用问题
将一个table复制给另外一个table,修改这个新的table值会影响原来的table,但通过clone可以改变这一行为
function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
9. 函数返回值
function f123()
return 1, 2, 3
end
function f456()
return 4, 5, 6
end
print(f123()) --1 2 3
print(f456()) --4 5 6
print(f123(), f456()) -- 1 4 5 6
print(f456(),1) --4 1
如果函数不是处于列的最后一个,只返回一个值
10.浮点数问题
这是浮点数都会有的精度丢失问题,lua也有这个问题。再看下整数与浮点数的比较
> =10==10.00000000000000000
true
> =10==10.00000000000000001
true
> =10==10.00000000000000000
true
> =10==9.999999999999999999
true
所以,这边测试了一下,lua 的浮点数会精确到15位,所以在比较精确的比较之前确认好精度在进行比较
11. 冒号语法
冒号语法可以用来定义函数, 这样的话,函数会有一个隐式的形参 self。
写法如下:
function t:f (params) body end
冒号语法实际上是一种语法糖,等效于:
t.f = function (self, params) body end
local t={a=123}
function t.f1(self, p)
print(self.a, p) --self.a 访问t中a的值
end
function t:f2(p)
print(self.a, p)
end
t:f1(1)
t.f1(t,1)
t:f2(1)
t.f2(t,1)
以上几个结果都是 123 1
这里,通过冒号方式调用函数不需要加入self参数,而点号则需要。
12. 函数闭包
当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量,这种特征我们称作词法定界。
function fn()
local i = 0
return function() -- 注意这里是返回函数的地址,不是执行
i = i + 1
return i
end
end
c1 = fn() -- 接收函数返回的地址
print(c1()) --> 1 --c1()才表示执行 ,i 此时为0
print(c1()) --> 2 --继续执行函数体 此时i =1上次执行的结果
如上,调用c1()时,fn函数明显已经返回,lua闭包闭包思想正确处理这种情况:
- 我们称i为从c1的外部局部变量(external local variable)或者upvalue。
- 简单的说,闭包是一个函数以及它的upvalues
如果我们再次调用fn,将创建一个新的局部变量i:
c2 = fn()
print(c2()) --> 1
print(c1()) --> 3
print(c2()) --> 2
13. 函数尾调用
- 尾调用是一种类似在函数结尾的goto调用。
- 当函数最后一个动作是调用另外一个函数时,我们称这种调用尾调用。
function f(x)
return g(x) -- 类似于goto g(x)函数的地址
end
- 尾调用不需要使用栈空间,因此尾调用递归的层次可以无限制的。
例如下面调用不论n为何值不会导致栈溢出。
function foo (n)
if n > 0 then return foo(n - 1) end
end
需要注意的是:必须明确什么是尾调用。
一些调用者函数调用其他函数后也没有做其他的事情但不属于尾调用。比如:
function f (x)
g(x)
return
end
上面这个例子中f在调用g后,不得不丢弃g地返回值,所以不是尾调用,同样的下面几个例子也不时尾调用:
return g(x) + 1 -- 还需+1
return x or g(x) -- 还需比较
return (g(x)) -- 还需调整为一个返回值
基础语句用法详细示例
--注释方式
--[[
多行注释
--]]
--********************变量类型********************
--lua中所有的变量 不需要申明变量类型
--lua中的所有变量 默认为全局变量 非全局前面加local
--lua中没有各种数值类型 统一都是Number类型 表示浮点数和
print("*************全局本地变量*************")
local a = 1 --局部 仅限于本文本访问 编程时 尽量都加local
print(a)
a1 = 1.5 --全局
print(a1)
--lua中只有false和nil才为假 0和空字符串为真
e = true;
print(e)
--lua中的string 可以用单引号或者双引号括起来
print("*************字符串相关*************")
b = '单引号字符串'
print(b)
c = "双引号字符串"
print(c)
--lua中字符串的换行 省略了\n换行替代符号
c = [[我是
你的
小宝贝
]]
print(c)
--字符串相关
str = "abCdefg"
print(string.upper(str))--小写转大写
print(string.lower(str))--大写转小写
print(string.reverse(str))--翻转字符串
print(string.find(str, "Cde"))--字符串索引查找
print(string.sub(str, 3))--字符串截取
print(string.rep(str, 3))--字符串重复
print(string.gsub(str, "Cd", "**"))--字符串修改
print(#str)--字符串长度
a = true
print(tostring(a));
print(string.format("我是%s,我今年%d岁了", "小宝贝", 2))--字符串长度
--lua中空的关键字时nil 相当于C#中的null
print("*************空引用*************")
d = nil
print(d)
print("*************类型获取*************")
--字符串拼接符号..
--type 类型判断
print("类型判断"..type(e))
--********************运算符********************
print("*************运算符*************")
--lua中没有自增减运算符
print("加法运算"..1+2)
print("余数运算"..9%2)
print("减法运算"..9-2)
print("乘法运算"..9*2)
print("除法运算"..9/2)
print("幂运算"..9^2)
--********************条件分支语句********************
print("*************条件分支语句*************")
a = 9
if a > 9 then
print("大于9")
elseif a >= 5 then
print("大于5")
elseif a == 3 then
print("值为3")
elseif a ~= 2 then --不等于
print("值为3")
end
--********************逻辑运算符********************
print("*************逻辑运算符*************")
a = true
b = false
if a and b then --逻辑与
print("大于9")
elseif a or b5 then --逻辑或
print("大于5")
elseif not a then -- 逻辑否
print("其它数")
end
--********************循环语句********************
print("*************循环语句*************")
--while 循环
print("*************while循环*************");
num = 0
while num < 5 do
print(num);
num = num + 1
end
--do while 循环
print("*************do while循环*************");
a = 1;
repeat
print(a);
a = a + 1
until a > 5
--for循环
print("*************for循环*************");
for i = 1,5 do --默认递增+1
print(i)
end
for i = 5,1,-1 do --递减1
print(i)
end
--********************函数********************
print("*************函数*************")
function f(x)
return x^2
end
print(f(2))
function f2(x2)
if x2 < 10 then
print("白卷")
elseif x2 < 60 then
print("分太低")
elseif x2 < 70 then
print("及格")
end
end
f2(2)
print("*************变长参数函数*************")
function ff( ... )
local arg = {...}
local total = 0
for i=1,#arg do
total = total + arg[i]
end
print(total)
end
ff(1,2,3,4,5,6)
print("*************函数嵌套*************")
function f3(x)
return function(y) return x + y end
end
a = f3(1)
print(a(2))
--********************复杂数据类型********************
print("*************复杂数据类型*************")
--所有的复杂类型都是table(表)
--数组
print("*************数组,列表*************")
--数组的存储类型可以混合,默认索引从1开始
a = {1,2,3,"12312",123123}
print(a[1])
print(a[4])
print(#a)--打印长度 从1开始计数
print("*************数组遍历*************")
for i=1,#a do
print(a[i])
end
--可以自定义索引 甚至负索引
print("*************自定义索引*************")
a = {[0]=1,2,3,[-1]=4,5}
print(a[0])
print(a[1])
print(a[-1])
print(a[2])
print(a[3])
print(#a)--打印长度 中间产生索引断裂了 会停止计数
print("*************二维数组*************")
a = {{1,2,3},{4,5,6}}
print(a[1][1])
print(a[1][2])
print(a[1][3])
print(a[2][1])
print(a[2][2])
print(a[2][3])
--迭代器遍历
print("*************ipairs迭代遍历键值*************")
a = {[0] = 1,2,[-1] = 3,4,5}
--遍历键值
for i,k in ipairs(a) do
print("ipairs遍历键"..i)
print("ipairs遍历值"..k)
end
print("*************pairs迭代遍历键值*************")
for i,k in pairs(a) do
print("pairs遍历键"..i)
print("pairs遍历值"..k)
end
print("*************迭代遍历键*************")
--遍历键
for i in pairs(a) do
print("键"..i)
end
print("*************字典*************")
a = {["1"] = 5, ["2"] = 4}
print(a["1"])
print(a["2"])
print("*************类*************")
student = {
--年龄
age = 1,
--性别
sex = 0,
--unity成绩
unity = 90,
--成长行为
Up = function(self)
print("我",self.age)
self.age = self.age + 1
print("我成长了"..self.age)
end,
--上课行为
Learn = function( )
print("学习")
end
}
student.Learn()
student.Up(student)
print("F-->",student.age)
student:Up()
student:Up()
--student.Learn()
student.age = 2
print(student.age)
print("*************特殊用法*************")
a,b,c = 1,2,3,4 --4会被忽略
print(a)
print(b)
print(c)
a,b,c = 1,2 --c会变为nil
print(a)
print(b)
print(c)
--多个返回值
function Test()
return 10,20,30,40
end
a,b,c = Test()
print(a)
print(b)
print(c)