print("hello lua")
lua官网
在线运行代码
数据类型
数据类型 | 描述 |
---|---|
number | 数字,可当作double,5/2 == 2.5 |
string | 字符串 |
nil | 空值,变量未赋值前都是nil,给变量赋值nil相当于释放变量 |
boolean | 布尔值,true和false |
table | 有两种形态:1. hash表 2. 数组 |
function | 函数,数据类型一种,可以赋值给变量或作为参数 |
userdata | 自定义数据,用于扩展,lua vm负责内存管理 还有种light userdata,可以理解成 void * ,值类型,不需要内存管理 |
字符串定义
四种字符串定义方式
text1 = "最普通的字符串"
text2 = '和"一样'
text3 = [[
长字符串定义,忽略任何转义,最前面的换行,会被忽略
]]
text4 = [===[
长字符串定义,忽略任何转义,加=号为了能在字符串里写 a[b[1]],=数量不限
]===]
关键字
and break do else elseif end false for function if in
local nil not or repeat return then true until while
关键字不能用用作变量名。特别的:a.end = 1
出错,但是可以用a["end"] = 1
注释
-- 单行注释
--[[
多行注释,-和[之前不能有空格
]]
数字运算
-
+ - * /
基本的加减乘除,注意5/2 == 2.5
-
%
取余,a%b
= $a - b * \lfloor {a/b} \rfloor$,可用于浮点数1%-1.5 == -0.5
-
^
幂乘,a^i
= $a^i$
字符串运算
-
..
字符串连接符,print("hello".." ".."world")
输出hello world
逻辑运算
-
== ~=
相等比较,任意类型都可以,注意2 ~= "2"
-
> < >= <=
大小比较,不能数字字符串混用,2 > "3"
会报错 -
not
非运算,not not a
相当于a ? true : false
-
and
与运算,a and b
相当于a ? b : a
,如果a为假值(nil
或者false
),返回a,否则返回b -
or
或运算,a or b
相当于a ? a : b
注意:
-
and
和or
的返回值不是bool类型的,而是参与运算的值的其中一个。 -
nil
和false
为假值,其他都是真值。也就是说,空串""
、数字0
和空表{}
都是真值。
变量
全局变量不需要声明,任何时候a = 10
都是有效的,在a被赋值前,取a的值返回nil
。
局部变量声明使用local
关键字,支持块作用域,支持一次声明多个。
local a,b = 1,2
if a then
local a,b = 10,20
print(a,b) -- 输出10 20
end
print(a,b) -- 输出1 2
补充:
局部变量性能好于全局变量,它的值在栈上,访问时用的索引。
全局变量是取的全局表。print(1)
等同于_G["print"](1)
。
可以修改下变成
local print = print
print(1)
赋值语句
lua的=
表达式比较特殊,支持一次赋值多个,多余的忽略,不够的补nil。
a, b = 1,2,3 -- 3忽略
c, d = 4 -- d是nil
交换x和y的值可以写成x,y = y,x
,十分方便。
条件语句
三个基本结构。
if x then
print("if语句,如果x为真,输出这句话")
end
if x then
print("if + else语句")
else
print("如果x为假,输出这句话")
end
if x then
print("if + elseif语句")
elseif y then
print("x为假,y为真,才输出这句话")
end
for循环
例子:
for i = 1,3 do
print(i)
end
输出 1,2,3
可以指定步长
for i = 1,3,2 do
print(i)
end
输出 1,3
补充:还有种for in
循环在table使用小节里介绍。
while循环
条件成立继续循环,例子:
local i = 1
while i <= 3 do
print(i)
i = i+1
end
repeat循环(不常用)
条件成立退出循环,例子:
local i = 1
repeat
print(i)
i = i + 1
until i > 3
break语句
可以用break退出上述三种循环。
注意:
- break需要是代码块的最后一个语句。
- 没有continue语句。
while true do
break --错误,后面还有代码
local i
end
while true do
do break end -- 正确.do XXX end 是一个的代码块,break 确实放在了这段代码的最后面
local i
end
table·数组
table的第一种形态:数组
1. 初始化
t = {1,2} -- 索引从数字1开始,相当于下面的例子
t = {};
t[1] = 1;
t[2] = 2;
2. 插入删除
t = {1,2,3}
table.insert(t,4) -- 在结尾追加4,变成{1,2,3,4}
table.remove(t) -- 移除结尾元素,变成{1,2,3}
table.remove(t,2) -- 移除第2个元素,变成{1,3},会移动后边的元素
3. 获取长度
t = {1,2,3}
print(#t) -- 3
4. 遍历
t = {1,2,3}
for i = 1,#t do
print(i .. " : " .. t[i]) -- 1:1 2:2 3:3
end
-- 这就是第二种for循环
for i,v in ipairs(t) do
print(i .. " : " .. v) -- 和上面一样的功能
end
6. 排序
t = {1,3,2}
table.sort(t) -- 1,2,3
table.sort(t,function(a,b) return a > b end) -- 3,2,1
注意:
- table当成数组使用,数字索引从1开始
- table当成数组用时,要保证是紧凑数组,索引1..n,
t[i] ~= nil -- i in [1,n]
,后面会说明为什么。
table·hash表
table当成hash表使用
1. 初始化
t = {["x"] = 10, ["y"] = 20}
t = {x = 10, y = 20} -- 字符常量索引,和上面一样
-- 多维数组
t = {
hp = 10,
pos = {100,200},
}
2. 删除
t = {x = 1, y = 2}
t["x"] = nil -- 删除key "x"
3. 遍历
t = {x = 1, y = 2}
for k,v in pairs(t) do
print(k .. ":".. v) -- x:1 y:2
end
注意:
- table的key(索引)可以是除nil以外的任何值,
t[nil] = 1
报错 - table的value(值)可以是任何值,特别的:
t['x'] = nil
的效果是删除t['x']
的值 -
t["x"]
可以简写成t.x
,x不能是关键字,t.end = 1
报错
table·不要数组和hash混用
table实际也可以混合数组和hash部分,如下
t = {
1,
["x"] = 2,
y = 3,
[4] = 4,
}
最好不要这么使用,数组和hash表是两个不同的语义结构,lua的table实现混合了他们,可以统一理解成hash表。
table使用有坑
其中最大的坑获取数组长度,lua提供了#
运算符。
但是:如果table的key不是1..n
,结果可能出错,因为这个返回的是一个n,满足t[n] ~= nil and t[n+1] == nil
。
t = {1,2}
t[3] = 1
print(#t) -- 数组是{1,2,3} 结果是 3
t[2] = nil
print(#t) -- 数组是{1,nil,3} 结果是1
如果是hash表,hash值作为索引,结果会更难预料。
所以说:table作为数组用,最好的紧凑数组
函数
两种函数声明形式
function func(a,b)
-- 先定义func变量,再定义函数,可以在这儿使用func递归调用
end
func = function(a,b)
-- 先定义了匿名函数,再赋值给变量func,这儿不能使用func递归调用
end
都是声明一个名字叫func
,参数是a,b
的函数。
参数不需要说明类型,返回值不需要说明。
函数可以返回任何个数的数据,使用return
返回,return
和break
一样,必须在代码块的最后面。
函数参数可以接受任意多个,使用...
来接受
function generate()
return 1,2,3
end
function MyPrint(...)
print("my print:",...)
end
MyPrint(generate()) -- my print: 1 2 3