目录
变量
Lua 中的一个变量可以随便赋值,自动识别类型
基本数据类型
--nil
a = nil
--number
a = 1
a = 1.2
--[[
string
Lua中双引号和单引号都代表string
--]]
a = "123"
a = '321'
--boolean
a = false
--获取变量类型
print(type(a))
--type 的返回值是string
变量的作用域
全局变量: 直接声明的变量,在全局有效,跨脚本也可使用
局部变量: local 修饰的变量,在局部有效
a = 10
t = {12, 3}
for i = 1, 1 do
--此处的 a 与外部的 a 是两个不同的变量
local a = t[i]
end
--打印 10
print(a)
字符串操作
--获取字符串的长度
--一个汉字占3个长度
str = "123abc汉字"
print(#str) --12
--多行字符串
s = "123\n123"
s = [[123
123]]
--字符串拼接符.. (+ - * / 是转换成number运算)
print(23 .. 32.2)
--format与c类似
print(string.format("占位符%.2f", 10.135))
--显示转换类型
tostring(str)
--常用操作:注意:大多数都不改变原字符串
--将字母进行大小写转换
string.upper(str)
string.lower(str)
--字符串反转
string.reverse(str)
--索引查找 返回第一次匹配的开始位置和结束位置
string.find(str, "123")
--截取字符串
string.sub(str, 3) --从第几个字符开始到结束
string.sub(str, 3, 5) --从第几个到第几个
--替换:返回替换后的字符串和替换次数
string.gsub(str, "12", "x")
--指定位置字符转ASCII码
string.byte(str, 2)
--ASCII码转字符
string.char(10)
运算符
算术运算符
+ - * / % ^
Lua没有自增和复合运算符
由于Lua只有number类型,所以 / 不会向下取整
小数也可取模
条件运算符
> < >= <= == ~=
逻辑运算符
and or not
有短路特性
-- and or 可以连接任何东西
-- 只有 nil 和 false 被认为是假
1 and 2 --返回 2
false and 2 --返回 false
false or 1 --返回 1
2 or 1 --返回 2
--由此特性实现三目运算符
res = (<condition>) and x or y
位运算符
Lua 中不支持位运算符
条件分支语句
if 条件 then
语句
elseif 条件 then
语句
else
语句
end
循环
--while 循环
while 条件 do
语句
end
--repeat until 循环
repeat
语句
until 条件 --此处是退出条件
--for 循环
for i = 1, 5 do --自动加1
语句
end
for i = 10, -1, 0 do
语句
end
函数
函数参数不对应的情况下,多的丢弃,少的为 nil
--写法1
function f(a, b)
print("f1")
end
--写法2
f2 = function(a, b)
return a, b --多返回值
end
Lua不支持函数重载
可变长参数
function f3(...)
arg = {...}
for i=1,#arg do
print(arg[i])
end
end
函数闭包
function f4(a)
--相当于返回了一个函数类型的变量,第一个参数已定,调用时只需填写第二个参数
return function(a, b)
return a + b
end
end
tmp = f4(1)
tmp(2)
表
实现数组
- Lua 索引从 1 开始
- 数组无效下标会返回 nil
- 使用 # 获取数组长度不可靠,会遇到 nil 截断
a = {1, nil, '2', true}
print(a[1])
print(#a) --输出 1
二维数组
a = {{1, 2, 3}, {4, 5, 6}}
-- 遍历
for i = 1, #a do
for j = 1, #a[i] do
print(a[i][j])
end
end
自定义索引
a = {[0] = 1, 2, 3, ['x'] = 'str'}
‘#’ 取长度是从索引 1 开始往后取连续的
迭代器遍历
ipairs 遍历
同 ‘#’ 一样,只能遍历从 1 开始连续的,遇到 nil 结束
for i, k in ipairs(b) do
print(i .. ' ' .. k)
end
pairs 遍历
可完整遍历各种不规则的表,遇到 value 为 nil 的跳过,但是不会截断
b = {[-1] = 1, ['123'] = 3, [2] = nil, [3] = 5}
for i, k in pairs(b) do
print(i .. ' ' .. k)
end
-- 打印结果
--[[
123 3
-1 1
3 5
--]]
实现字典
a = {['name'] = 'jack', ['age'] = 18, ['1']}
--访问
print(a['name'])
--或者(只有合法的标识符才能这么使用)
print(a.name)
--删除
a[xxx] = nil
--遍历
for i, k in pairs(a) do
print(i, k)
end
实现类
Lua 中可以使用表来实现类似类的结构
Person = {
--与 ['name'] = 'Jack' 是等价的
name = 'Jack',
age = 18,
Work = function()
print(Person.name .. 'work')
end
}
Person.name = 'Tom'
Person.Work()
-- 添加新的成员
Person.Eat = function(t)
print(t.name .. 'eat')
end
Person.Eat(Person)
--[[
调用时使用 :运算符 表示将自己作为第一个参数
声明时使用 :运算符 self 表示第一个参数
--]]
function Person:Eat()
print(self .. 'eat')
end
Person:Eat()
公共操作
插入:
table.insert(t, b): 将 b 插入至 t 末尾
t1 = {{name = 'mh13', age = 1}, {name = '567', age = 20}}
t2 = {job = 'xx'}
table.insert(t1, t2)
删除:
table.remove(t): 移除 t 最后一个元素
table.remove(t, index): 移除指定位置的元素
t1 = {name = '123', age = 18}
table.remove(t1)
排序
table.sort(t, cmp): 传入表和比较器,不传默认为升序
带自定义索引的无法被排序
根据 key 排序的思路:
将 key 存入另一个 table 中排序,在根据排序后的结果来获取 value
t = {1,2,3,5,4,3,56,1,3,1,2}
--升序排序
table.sort(t)
for _,v in pairs(t) do
print(v)
end
--降序排序
table.sort(t, function(a, b) return a > b end)
for _,v in pairs(t) do
print(v)
end
合并
table.concat(t, separater): 将表中的元素拼接在一起
t = {'23', 'xxx', 'sjdkl'}
table.concat(t, '+')
大G表
存储了所有全局变量的总表
for k, v in paris(_G) do
print(k, v)
end
多脚本执行
--加载并执行一次,之后require不会再执行
--脚本是可以有返回值的!!
tmp = require('xx')
--返回该脚本是否被加载
print(package.loaded['xx'])
--卸载脚本
package.loaded['xx'] = nil
--再次加载执行
require('xx')
协同程序
创建协程
function fun()
for i = 1, 10 do
print(i)
end
end
--创建协程方式一
co = coroutine.create(fun)
--创建协程方式二:返回函数类型
co2 = coroutine.wrap(fun)
print(type(co2)) --function
运行协程
--协程运行对应方式一
coroutine.resume(co)
--协程运行对应方式二
co2()
协程挂起
--协程挂起
--相当于暂停该协程,下次再次resume的时候继续执行
fun2 = function()
local i = 1
while true do
print('running' .. i)
i = i + 1
coroutine.yield(1)
--或者可以有返回值
--coroutine.yield(i)
end
end
co3 = coroutine.create(fun2)
coroutine.resume(co3)
coroutine.resume(co3)
--获取返回值
--第一个返回值是协程是否启动成功
--第二个返回值是yield中的返回值
isOk, tmp = coroutine.resume(co3)
--对应方式二
co4 = coroutine.wrap(fun2)
co4()
co4()
--这种方式创建的协程只有yield的返回值
tmp = co4()
协程状态
--协程状态
--dead 结束
--suspended 暂停
--running 执行中
print(coroutine.status(co3))
--返回当前正在运行的协程
--在协同方法内部才可能获取到(毕竟协程是单线程的)
print(coroutine.running())
元表
--元表特殊方法
meta = {
--相当于重写了tostring
__tostring = function(t)
return t.name
end,
--当子表被当作函数调用时执行的内容
--第一个参数是子表其本身
__call = function(t)
print(t.name .. 'call')
end,
--当子表中找不到某个索引时
--会到元表__index 指向的表中去找
--注意:__index 最好在外部初始化
--否则可能导致指向meta本身无效
__index = {age = 1},
--子表如果赋值一个不存在的索引,
--那么会把值赋给__newindex 指向的表中
--子表不会改变
__newindex = {},
--运算符重载
--+
__add = function(t1, t2)
return 0
end,
---
__sub = function(t1, t2)
return 0
end,
--*
__mul = function(t1, t2)
return 0
end,
--/
__div = function(t1, t2)
return 0
end,
--%
__mod = function(t1, t2)
return 0
end,
--^
__pow = function(t1, t2)
return 0
end,
--==
__eq = function(t1, t2)
return true
end,
--<
__lt = function(t1, t2)
return true
end,
--<=
__le = function(t1, t2)
return true
end,
--..
__concat = function(t1, t2)
return ''
end,
}
--子表
t = {
name = 'Hurric'
}
--设置、获取元表
setmetatable(t, meta)
print(getmetatable(t))
--__tostring
print(t)
--__call
t()
--__index指向表
print(t.age)
--忽略__index,在t表中查询
print(rawget(t, 'age'))
--忽略__newindex,在t表中赋值
rawset(t, 'age', 3)
Lua 面对对象
封装
Object = {}
Object.id = 1
--创建对象的方法
function Object:new()
local obj = {}
self.__index = self
setmetatable(obj, self)
return obj
end
local myObj = Object:new()
print(myObj.id) --1
myObj.id = 2
print(myObj.id) --2
继承
--创建子类的方法
function Object:subClass(className)
--在大G表中新增一个表
_G[className] = {}
local obj = _G[className]
self.__index = self
--在子类中存储父类对象,以便于子类调用父类方法
obj.base = self
setmetatable(obj, self)
return obj
end
--新建Object的子类Student
Object:subClass('Student')
print(Student.id)
--由于子类没有new方法
--所以会寻找元表Object __index指向的表Object中的方法
--调用了父类的new方法
stu = Student:new()
print(stu.id)
多态
--建立 GameObject 类
Object:subClass('GameObject')
GameObject.value = 0
function GameObject:Add()
self.value = self.value + 1
print(self.value)
end
--建立 GameObject 子类 Player
GameObject:subClass('Player')
--重写方法
function Player:Add()
--当需要调用base的方法时
--应避免将base作为参数传入
--否则修改的是所有子类共用的父类表
--传入self才是在子表中新增索引与值
self.base.Add(self)
end
local p1 = Player:new()
p1:Add()
--第二次应打印 1
local p2 = Player:new()
p2:Add()
Lua自带库
时间库
--系统时间
print(os.time()) --打印一个number
--传入参数 得到时间
print(os.time({year = 2014, month = 8, day = 14}))
local nowTime = os.date('*t')
for k, v in pairs(nowTime) do
print(k, v)
end
数学库
print(math.abs(-1))
--弧度转角度
print(math.deg(math.pi))
print(math.cos(math.pi))
--取整
print(math.floor(-1.6))
print(math.ceil(1.1))
--最大值最小值
print(math.max(1, 2))
print(math.min(21, 1))
--整数小数部分拆分
print(math.modf(1.2))
--随机数
--随机数种子
math.randomseed(os.time())
print(math.random(100)) --1~100
print(math.random(100))
--开方
print(math.sqrt(4))
路径
不常用
--脚本加载路径
print(package.path)
--可以修改
package.path = package.path .. ';C:\\'
Lua垃圾回收
g = {name = 'xxx', age = 18}
--获取当前占用字节数,单位为K
print(collectgarbage('count'))
--置空即为变为垃圾
g = nil
--进行垃圾回收
collectgarbage('collect')
print(collectgarbage('count'))
lua中有自动定时进行GC的方法,但较为消耗性能
Unity中热更新开发,尽量手动调用GC