Lua 基础

变量

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值