当前位置: 首页 > news >正文

Unity热更新——AB包和Lua

AB包:

1.是什么?

是特定平台的资产压缩包,包括(模型,贴图,预制体,音效,材质球)
Resources:核心必需资源 + 常驻内存 + 不热更,主打 “随用随取、不用折腾”;
AB 包:非必需资源 + 动态加载 / 卸载(省内存) + 支持热更,主打 “灵活可控、适配手游场景”。

2.有什么用?

打包层面,相较于resources的资源打包,可以指定,位置,压缩方式(减小包大小)还可以动态更新(热更新)

3.生成打包AB包

Asset Bundle Browser资源包,unity已经2020后取消了
然后就可以选择要打包的资源了。
然后在Windows工具栏里面就有了,完事呢(中间有一个打包页签):
在这里插入图片描述

4.使用解包AB包

同一个ab包不能重复加载包

加载ab包和里面的资源:

同步:

        //加载AB包AssetBundle ab= AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/"+"f");//包名//加载AB包里面的资源GameObject obj=ab.LoadAsset<GameObject>("Cube");GameObject obj2=ab.LoadAsset("Cube",typeof(GameObject)) as GameObject;Instantiate(obj);

异步:

        StartCoroutine(LoadABRes("f","Cube"));}//异步不知到什么时候成功,所有要携程,本质不依赖携程的分时执行,只是要携程的顺序执行IEnumerator LoadABRes(string ABname,string RESname){AssetBundleCreateRequest AB=AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABname);yield return AB;AssetBundleRequest ab= AB.assetBundle.LoadAssetAsync(RESname,typeof(GameObject));yield return ab;GameObject jg= ab.asset as GameObject;Instantiate(jg);}

卸载ab包以及是否影响已经使用的资源:

			//false不影响,true影响ab.unLoad(true);//单个AssetBundle.UnloadAllAssetBundles(false);//全部

5.AB包依赖:

某个包里面的资源的组成部分都会也必须在ab包里面。
当需要的组成部分和资源不在一个包:1,放一个包,2,加载资源们所在包(解压缩到内存占据容器)3,使用主包找某个包的依赖包(主包名字在biudin里面可以看)

        //加载主包StandaloneWindowsAssetBundle zhu = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "StandaloneWindows");//加载主包固定文件夹:AssetBundleManifest abManifest = zhu.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//从固定文件夹得到依赖信息string[] strs = abManifest.GetAllDependencies("one");for (int i = 0; i < strs.Length; i++){Debug.Log(strs[i]);AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);}AssetBundle one= AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "one");GameObject obj=one.LoadAsset("Cube",typeof(GameObject)) as GameObject;Instantiate(obj);

右键我们的主包就是默认包可以看到里面每个自定义包的依赖包:
在这里插入图片描述

6.AB包资源加载管理器

用到了之前封装好的这个mono单例模块,毕竟是个管理器

using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Events;public class ABMsg : SingletonAutoMono<ABMsg>
{private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();private AssetBundle mainAB = null;private AssetBundleManifest mainfest = null;/// <summary>/// 获取AB包的路径/// </summary>private string PathUrl{get{return Application.streamingAssetsPath;}}/// <summary>/// 主包名,随着平台改变/// </summary>private string MainABName{get{
#if UNITY_IOSreturn "IOS";
#elif UNITY_ANDROIDreturn "Android";
#else return "StandaloneWindows";
#endif}}/// <summary>/// 代码复用,实现多形式同步加载资源/// </summary>/// <param name="abName"></param>public void LoadAB(string abName){//加载主包if (mainAB == null){string mainABPath = System.IO.Path.Combine(PathUrl, MainABName);mainAB = AssetBundle.LoadFromFile(mainABPath);mainfest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");}//获取并加载依赖包string[] dependencies = mainfest.GetAllDependencies(abName);for (int i = 0; i < dependencies.Length; i++){if (!abDic.ContainsKey(dependencies[i])){string depPath = System.IO.Path.Combine(PathUrl, dependencies[i]);AssetBundle depAB = AssetBundle.LoadFromFile(depPath);if (depAB != null){abDic.Add(dependencies[i], depAB);}else{Debug.LogError("加载依赖AB包失败: " + depPath);}}}//加载目标包if (!abDic.ContainsKey(abName)){string abPath = System.IO.Path.Combine(PathUrl, abName);if (!System.IO.File.Exists(abPath)){Debug.LogError("目标AB包不存在: " + abPath);return;}AssetBundle targetAB = AssetBundle.LoadFromFile(abPath);if (targetAB != null){abDic.Add(abName, targetAB);}else{Debug.LogError("加载目标AB包失败: " + abPath);return;}}}//同步加载资源(普通)public Object LoadRes(string abName, string resName){LoadAB(abName);//加载并返回资源Object res = abDic[abName].LoadAsset(resName);if (res == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}return res;}//同步加载资源(泛型)public Object LoadRes<T>(string abName, string resName) where T:Object{LoadAB(abName);//加载并返回资源T res = abDic[abName].LoadAsset<T>(resName);if (res == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}return res;}//同步加载资源(类型)public Object LoadRes(string abName,string resName,System.Type type){LoadAB(abName);//加载并返回资源Object res = abDic[abName].LoadAsset(resName,type);if (res == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}return res;}//异步加载(协程是为了管理异步阶段,比较后台不阻塞需要一个携程得到当异步准备好了后触发回调委托)public void LoadResAsync(string abName,string resName,UnityAction<Object> callback){StartCoroutine(ReallyLoadResAsync(abName,resName,callback));}private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callback){LoadAB(abName);//加载并返回资源AssetBundleRequest rab = abDic[abName].LoadAssetAsync(resName);yield return rab;if (rab.asset == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}else{callback(rab.asset);}}//异步加载(泛型)public void LoadResAsync<T>(string abName, string resName, UnityAction<Object> callback){StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callback));}private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<Object> callback){LoadAB(abName);//加载并返回资源AssetBundleRequest rab = abDic[abName].LoadAssetAsync<T>(resName);yield return rab;if (rab.asset == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}else{callback(rab.asset);}}//异步加载(类型)public void LoadResAsync(string abName, string resName,System.Type type, UnityAction<Object> callback){StartCoroutine(ReallyLoadResAsync(abName, resName,type, callback));}private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callback){LoadAB(abName);//加载并返回资源AssetBundleRequest rab = abDic[abName].LoadAssetAsync(resName,type);yield return rab;if (rab.asset == null){Debug.LogError($"在AB包 {abName} 中找不到资源: {resName}");}else{callback(rab.asset);}}//卸载单个AB包public void UnloadAB(string abName, bool unloadAllLoadedObjects = false){if (abDic.ContainsKey(abName)){abDic[abName].Unload(unloadAllLoadedObjects);abDic.Remove(abName);}}//卸载全部AB包public void UnloadAll(){AssetBundle.UnloadAllAssetBundles(false);abDic.Clear();mainAB = null;mainfest = null;}
}

使用:

    private void Start(){Object x=ABMsg.GetInstance().LoadRes("one", "Cube");Object y=ABMsg.GetInstance().LoadRes<GameObject>("one", "Cube");ABMsg.GetInstance().LoadResAsync("one","Cube",typeof(GameObject),cc);ABMsg.GetInstance().LoadResAsync<GameObject>("one","Cube",cc);Instantiate(x);Instantiate(y);}public void cc(object a){Instantiate(a as GameObject);print("你好");}private void Update(){}

Lua热更新:

用vscode可以写,但是我们目前用这个sublime text超强文本编辑器

1.快捷键:

ctrl+B运行
选择open 文件夹=打开文件夹做这个目录吧

2.lua语法:

第一个程序

print("*********第一个程序*********")
--单行注释
print("你好世界")--可以省略分好
print("你好世界")
--[[
第一种多行注释
]]
--[[
第二种多行注释
]]--
--[[
第三种多行注释
--]]

在这里插入图片描述

变量

print("**********变量********")
--lua当中的简单变量类型
--nil number string boolean
--lua中的变量申明不需要变量类型,会自动判断
print("**********nil********")
print(b)--没有声明过的变量默认为nil空
a = nil
print(type(a))--可以使用这个函数得到类型,这个函数的返回值是string
print(type(type(a)))
print(a)
print("**********number********")
a=1
print(a)
a=1.99
print(a)
print("**********string********")
a="123"
print(a)
a='123'
print(a)
print("**********boolean********")
a=true
print(a)
a=false
print(a)
--lua当中的复杂变量类型
--function函数 table表 userdata数据结构 thread协同程序

在这里插入图片描述

字符串操作

print("*********字符串操作*********")
str="nihao你好"--英文占一个字符,中文占三个
print("*********字符串长度*********")
print(#str)
print("*********字符串换行*********")
print("123\n123")
s=[[第一行
第二行
第三行
]]
print(s)
print("*********字符串拼接*********")
print("123"..111.9)
print(string.format("我是%s,我今年%d","xzc",19))
print("*********转字符串*********")
print(tostring(true))
print("*********公共方法*********")
print(string.upper(str))--大写
print(string.lower(str))--小写
print(string.reverse(str))--翻转
print(string.find(str,"好"))--索引从一开始,并且返回的是字节第一个和最后一个
print(string.sub(str,3,4))--截取>=3<=4
print(string.rep(str,4))--重复
print(string.gsub(str,"你好","你坏"))--修改(修改了多少次)
a=string.byte("Lua",1,3)--转ascll妈>=1<=3区间
print(a)
print(string.char(a))--ascll码转字符串

在这里插入图片描述

运算符

print("*********运算符*********")
print("*********算数运算符*********")
-- + - * / %
-- 没有自增自减++ --
--没有复合运算符 += -= /= *= %=
-- 字符串在运算符里面自动转换成number如果可以
print((1+2).."|"..(1-2).."|"..("12"*2).."|"..(9/3).."|"..(9%2))
print("幂运算"..2^3)
print("*********条件运算符*********")
--> < >= <= ~=
print(1~=9)
print("*********逻辑运算符*********")
-- && ||  ! and or not"遵循前面满足后面不执行,短路“
print(true and false)
print(true or false)
print(not (true and false))
print("*********位运算符*********")--不支持print("*********三目运算符*********")--不支持

在这里插入图片描述

条件分支

print("*********条件分支*********")
a=5
if a<5 thenprint("1")
elseif a>5 thenprint("2")
elseprint("3")
end

在这里插入图片描述

循环语句

print("*********循环语句*********")
print("*********while语句*********")
num=0
while num<5 doprint(num)num=num+1
end
print("*********do while语句*********")num=0repeat
print(num)
num=num+1until num>5--结束条件
print("*********for语句*********")
for i=1,10,2 do--i默认从初+第三个参数(默认1)print(i)
end

在这里插入图片描述

函数

print("*********函数*********")
print("*********无参无返回值*********")
function F(  )
print("s")
endF(  )F1=function()
print("b")
end
F1()
print("*********有参数*********")
function F2(A)print(A)
endF2()
F2("1","2")
F2('1')
F2(12.9)
print("*********有返回值*********")
function F3(a)print(a)return a,"123",true--多返回值和接取
end
x,y,z,s=F3(11.3)
print(x,y,z,s)print("*********函数类型*********")
F4=function (  )-- body
end
print(type(F4))
print("*********函数重载*********")
--函数名相同,函数参数类型和个数不同,但是天然就是支持不同类型和不同参数
--不支持
print("*********变长参数*********")
function F5( ... )--要先用一个表存起来arg={...}for i=1,#arg doprint(arg[i])end
end
F5("1",2,true)
print("*********函数嵌套*********")
function F6()F7=function()print(123)end
return F7
end
F8=F6()
F8()

在这里插入图片描述

表table

print("*********复杂数据类型表talbe*********")
--所有数据类型的根基
print("*********数组*********")
a={1,2,"s",true,nil}
print(a[0])--表的索引第一位是1
print(#a)--中间为空就会断
print("*********数组遍历*********")
for i=1,#a doprint(i)
end
print("*********二维数组*********")
a={{1,2,3},{4,5,6}}
print(a[1][1])
print("*********二维数组遍历*********")
for i=1,#a dob=a[i]for j=1,#b doprint(b[j],a[i][j])end
end
print("*********自定义索引*********")
aa={[0]=1,2,3,[-8]=4,5}--跳过的索引为nil
for i=-8,#aa doprint(aa[i])
end

在这里插入图片描述

i.pairs迭代器遍历


print("*********ipairs迭代器遍历(拉)*********")
--迭代器遍历 主要是用来遍历表的
--#得到的数组长度,受nil中断,自定义索引也会有坑
a={[0]=1,2,[-1]=3,4,5,[9]=100}
for i,k in ipairs(a) doprint(i..k)--ipairs遍历是从1开始遍历,小于等于0的值得不到,--中间断了也不成end
print("*********pairs迭代器遍历(ok)*********")
for i,k in pairs(a) do--两个接着,table内容本质就是键值对print("pairs"..i..k)
end

在这里插入图片描述

表table2

print("*********复杂数据类型表talbe-2*********")
print("*********字典*********")
print("*********字典的申明*********")
a={["name"]="xzc",["age"]=14,["1"]=5}--声明(table可以自定义键)
a.name="dy"--修改
a["2"]=100--增加
a["2"]=nil--删除,因为不加默认是nilb
print(a["name"],a.age,a["1"],a["2"])--可以直接点,但是不能是数字
print("*********字典的遍历*********")
for k,v in pairs(a)doprint(k,v)
endprint("*********类和结构体*********")
--默认没有面向对象,需要自己实现
student={
age=1,
sex=true,
up=function(x)--print(age)--成员之间不能直接调用print(student.age)print("成长函数",x)
end
}
student.name="t"
--lua的table中.和冒号区别
student.up()
student:up()--冒号调用会默认吧冒号者当第一个参数传入。self表示该函数的第一个参数
for i,j in pairs(student)doprint(i,j)
endprint("*********表的公共操作*********")
--表中table的公共操作
t1={{age=1,name="123"},{age=1,name="345"}}
t2={name="xzc",sex=true}
print("*********插入*********")
print(#t1)
table.insert(t1,t2)--插入
t2={name="xzc",sex=true}
print(#t1)
print("*********删除*********")
table.remove(t1,2)--删除指定,默认为1
print(t1[2].name)
print("*********排序*********")
t2={5,8,2,5}
table.sort( t2)
for i,j in pairs(t2) doprint(j)
end
table.sort( t2,function(a,b)if a>b thenreturn trueend
end)
for i,j in pairs(t2) doprint(j)
end
print("*********拼接*********")
t2={20,1,"nihao"}--数字,字符串
str=table.concat( t2, ",",1,2 )
print(str)

在这里插入图片描述

多脚本执行

print("*********多脚本执行*********")
print("*********全局本地变量*********")
for i=1,2 doc="xzc"--全局变量local d = 1--局部变量
end
print(c)
print(d)
print("*********多脚本执行*********")
--关键字require("脚本名")
print(aa)
require("first")--执行过了就可以使用另外一个脚本的访问权限满足的东西
require("first")--不能多次执行
print(require("first"),"返回值")--还可以得到另外脚本返回值
print(aa)
print(bb)
print("*********脚本卸载*********")
--关键字package.loaded["脚本名"]可以得到返回值判断是否被加载
print(package.loaded["first"])
package.loaded["first"]=nil
print(package.loaded["first"])
print("*********大G表*********")
--大G表(_G)是一个总表table,会把所有全局变量都存储
--for k,v in pairs(_G)do
--	print(k,v)
--end
aa="123"
local bb = 1
print("first")
return 'ok'

在这里插入图片描述

Lua的特殊用法

print("*********特殊用法*********")
print("*********多变量赋值*********")
a,b,c,d=1,true,"你好"--多变量为空,少变量取前
print(a,b,c,d)
print("*********多返回值*********")
function z()return 1,2,3
end
a,b,c,d=z()
print(a,b,c,d)--多变量为空,少变量取前
print("*********and or*********")
--不止链接bool,只有nil,false是假,反正会程、返回代表真假的东西而不是true,false
print(nil and 1)
print(true and 1)
print(nil or 1)
print(nil or false)
print(false or nil)
--模拟三目运算符
xx=(1>3)and"ok"or"no"
print(xx)
xx=(1<3)and"ok"or"no"
print(xx)

在这里插入图片描述

协程

print("*********协程*********")
print("*********协程创建*********")
function a()print(123)
end
--coroutine.create(),返回线程类型
co = coroutine.create(a)
print(co,type(co))
--coroutine.wrap(),返回函数类型
co2 = coroutine.wrap(a)
print(co2,type(co2))print("*********协程运行*********")
--coroutine.resume()
coroutine.resume(co)
--直接调用函数
co2()
print("*********协程挂起*********")
function b(  )local i=1while true doprint(i)i=i+1print(coroutine.status(co3))coroutine.yield(i)end
end
--方式一:
co3=coroutine.create(b)
isok,re=coroutine.resume(co3)--第一个返回值是携程是否成功,第二个是返回值
print(isok,re)
isok,re=coroutine.resume(co3)
print(isok,re)
--方式二:
co4=coroutine.wrap(b)
co4()
re=co4()
print("返回值"..re)--第一个返回值就是写的返回值
print("*********协程状态*********")
--coroutine.status()
--dead结束
--suspended暂停
--running运行中
print(coroutine.status(co))
print(coroutine.status(co3))
--还有函数可以得到正在运行协程的线程号
print(coroutine.running())

在这里插入图片描述

元表

print("*********元表*********")
print("*********元表概念*********")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都能拥有自己的元表(父)
--当我们子表中进行特定操作时,会执行元表内容
print("*********设置元表*********")
meta={}
myTable={}
--设置元表函数
--第一个参数(子表)。第二个参数(元表)(父)
setmetatable(myTable,meta)
print("*********特定操作*********")
print("*********特定操作__tostring*********")
mate2={--当子表要被当string使用时,会默认调用原表的__tostring()方法__tostring=function(t )--默认将自己作为第一个参数赋值return t.nameend
}
myTable2={name="xzc"
}
setmetatable(myTable2,mate2)
print(myTable2)
print("*********特定操作__call*********")
mate3={--当子表要被当string使用时,会默认调用原表的__tostring()方法__tostring=function(t)--默认将自己作为第一个参数赋值return t.nameend,--当子表要被当函数  使用时,会默认调用原表的__call()方法__call=function(a,b)--默认将自己作为第一个参数赋值print(a)print("oi"..b)end
}
myTable3={name="xzc"
}
setmetatable(myTable3,mate3)
myTable3("你好")
print("*********特定操作__运算符重载*********")
mate4={__add=function(a,b)return a.age+b.ageend,__sub=function(a,b)return a.age-b.ageend,__mul=function(a,b)return a.age*b.ageend,__div=function(a,b)return a.age/b.ageend,__mod=function(a,b)return a.age%b.ageend,__pow=function(a,b)return a.age^b.ageend,__eq=function(a,b)--比较return a.age==b.ageend,__lt=function(a,b)return a.age<b.ageend,__le=function(a,b)return a.age<=b.ageend,__concat=function(a,b)--..return "a.age..b.age"end,}
MyTable4={age=10
}
setmetatable(MyTable4,mate4)
print(MyTable4+MyTable4)
--条件运算符的重载要求两个表的元表一致
print("*********特定操作——index和newIndex*********")
---当表找不到属性会去找元表中__index指定的表的属性()
mate6 ={age = 1--__index={age = 1}
}
--下面这个代码要是写内部,会有坑,因为声明的同时不能立马用
mate6.__index=mate6
myTable6={}
setmetatable(myTable6,mate6)
print(mate6.age)
--当赋值时,如果赋值一个不存在的索引,那么会把责怪值赋值到newubdex所指表中,不改自己()
mate7={}
mate7.__newindex={age=1}
MyTable7={}
setmetatable(MyTable7,mate7)
MyTable7.age=11
print(mate7.__newindex.age)
print("*********其他操作*********")
--获取元表
print(getmetatable(MyTable7))--对标settmetatable
--忽视__index设置,只能自己表内找
print(rawget(MyTable7,"age"))
--忽视__newindex设置,如果表没有直接给表加上没有的
rawset(MyTable7,"age",99)
print(MyTable7.age)

在这里插入图片描述

面向对象

print("*********面向对象*********")
print("*********封装*********")
--调用时候用“:”,self赋值。声明时候“:”提供默认self防止没人:调用,但是要用self.
Object={}
Object.id=1--添加成员变量
--实现封装一个类,可以被new
function Object:new()--添加成员函数local obj = {}--元表self.__index=self--self.__newindex=self//只允许得父类,不允许改父类,改的话就自己私有的了setmetatable(obj,self)return obj
end
function Object:hs()
print(self.id)
end
local myObj=Object:new()
myObj.id=10
myObj:hs()
print(Object.id)
print("*********继承*********")
--写一个继承方法.创建一个表并且继承:调用者
function Object:subClass(className)_G[className]={}--声明一张全局表local obj=_G[className]self.__index=selfobj.base=self--自己定义base保留父类setmetatable(obj,self)
end
Object:subClass("Person")--我们对于冒号声明的函数都要注意预留第一个参数,除非也是冒号调用
x=Person:new()
print(x.id)
print("*********多态*********")
--相同方法不同执行逻辑
Object:subClass("GameObject")
GameObject.posX=0;
GameObject.posY=0;
GameObject.posZ=0;
function GameObject:Speak()print(self.posX,self.posY,self.posZ)
end
GameObject:subClass("Player")
function Player:Speak()
--self.base:Speak()--相当于传递的Gameobject的,改同一个父类
self.base.Speak(self)
print("重写")
end
yy=Player:new()
yy:Speak()
yx=Player:new()
yx:Speak()

在这里插入图片描述

封装面向对象

--面向对象实现
--基类Object
Object={}
--new()方法->体现封装
function Object:new( )--声明空表local obj={}--关联self表为元表,设置元表的__index属性self.__index=selfsetmetatable(obj,self)--返回链接好元表的空表return obj
end
--继承方法->体现继承
function Object:subClass( className )--使用大G表声明一个全局的表,创建一个继承某类的类_G[className]={}local obj=_G[className]--关联self表为元表,设置元表的__index属性self.__index=selfsetmetatable(obj,self)--为新诞生类添加一个成员属性,存储父类,以便实现多态obj.base=self
endObject:subClass("GameObject")
GameObject.x=0
GameObject.y=0
function GameObject:SP(  )self.x=1self.y=9
end
go=GameObject:new()
print(go.x,go.y)
go:SP()
print(go.x,go.y)
GameObject:subClass("Player")
function Player:SP()print("重载SP:")self.base.SP(self)--得吧self传第一个参数,而不是base,子类使用父类方法,而不是直接拿父类方法self.x=self.x+1self.y=self.y+1
end
p=Player:new()
print(p.x,p.y)
p:SP()
print(p.x,p.y)

在这里插入图片描述

自带库

print("*********自带库*********")
print("*********时间*********")
-- 1. 时间戳
print("当前时间戳:", os.time())
print("指定时间戳(2024-08-14):", os.time({year=2024, month=8, day=14}))-- 2. 格式化获取当前时间
local currentDate = os.date("%Y-%m-%d") -- 年-月-日
local currentTime = os.date("%H:%M:%S") -- 时:分:秒
local fullTime = os.date("%Y-%m-%d %H:%M:%S") -- 完整时间(年-月-日 时:分:秒)print("\n当前日期:", currentDate)
print("当前时间:", currentTime)
print("完整时间:", fullTime)-- 3. 单独获取每个时间字段(按需提取)
local year = os.date("%Y")
local month = os.date("%m")
local day = os.date("%d")
local hour = os.date("%H")
local min = os.date("%M")
local sec = os.date("%S")
local week = os.date("%w") -- 星期(0=周日,1=周一,...,6=周六)print("\n单独字段:")
print("年:", year)
print("月:", month)
print("日:", day)
print("时:", hour)
print("分:", min)
print("秒:", sec)
print("星期(0=周日):", week)print("\n*********数学*********")
-- 数学库常用示例
--先设置随机数种子
math.randomseed(os.time())
print("随机数(0-1):", math.random())
print("随机数(1-100):", math.random(1, 100))
print("绝对值:", math.abs(-456))
print("平方根:", math.sqrt(25))
print("最大值(3,7,2):", math.max(3, 7, 2))
print("最小值(3,7,2):", math.min(3, 7, 2))
print("圆周率:", math.pi)
print("正弦值(π/2):", math.sin(math.pi/2)) -- 结果接近 1
print("弧度转角度",math.deg(math.pi))
print("向上取整",math.floor(2.6))
print("向下取整",math.ceil(2.6))
print("小数分离",math.modf(1.2))
print("\n*********路径*********")
--lua脚本加载路径
print(package.path)
package.path=package.path.."C:\\"
print(package.path)

在这里插入图片描述

垃圾回收

print("*********垃圾回收*********")
--关键字collectgarbage
--获取当前lua占用内存数kb,返回值*1024=字节
print(collectgarbage("count"))
test={id=20,name="你好"}
print(collectgarbage("count"))
--垃圾回收(对标GC)
test=nil--解除羁绊就是变垃圾
collectgarbage("collect")
print(collectgarbage("count"))
--lua有自动计时进行GC方法

在这里插入图片描述

3.简单闭包:定义+意义

1. 定义

闭包 = 内部函数 + 捕获的外部函数局部变量
核心特点:内部函数被返回后,依然能访问/修改外部函数的局部变量(这些变量不会随外部函数执行结束而消失)。

function 外部函数()local 局部变量 = 0  -- 外部函数的局部变量return function()  -- 返回内部函数(闭包)局部变量 = 局部变量 + 1print(局部变量)end
endlocal 闭包实例 = 外部函数()
闭包实例()  -- 输出1(记住了局部变量)
闭包实例()  -- 输出2(继续修改局部变量)

2. 意义

核心意义:让函数带“记忆”,同时不污染全局变量
用大白话讲2个关键作用:

  1. 不用全局变量,也能让函数记住之前的状态(比如计数器、累加器);
  2. 保护变量不被随意修改(外部只能通过闭包接口操作,不能直接改)。

3.对比:不用闭包的麻烦

如果不用闭包,想实现计数器只能用全局变量:

local 全局变量 = 0  -- 容易被其他代码误改
function 计数()全局变量 = 全局变量 + 1print(全局变量)
end

而闭包能让“状态”(局部变量)和“操作”(内部函数)绑在一起,既安全又干净。

http://www.dtcms.com/a/609703.html

相关文章:

  • jail瘦虚拟机创立实践@FreeBSD14.3
  • 科技有限公司网站企业信用公示信息网
  • ATT 语法 x86-64 汇编核心知识点总结(附实战案例)
  • 点量云流突破架构壁垒,实现全栈信创自主可控
  • C语言编译成汇编 | 深入理解编译过程与底层实现
  • 一个网站源码值多少钱网站建设初期目标
  • list集合使用
  • DuoPlus更新|新增云手机自定义SIM号码、代理备注等多重功能!
  • 安卓手机/平板/TV版 Rotation强制横屏显示工具!免ROOT可用!再推荐突破手机限制的3款神器
  • Gopeed+cpolar:跨平台下载任务的云端穿透解决方案
  • 手机Basic语言编译器 | 专为手机开发的编程工具与应用场景分析
  • 驾校网站建设滴滴友链
  • Modbus TCP 转 Modbus RTU物联网网关实现光伏产线西门子与罗克韦尔PLC互联
  • Sharding-jdbc 假如全表有20年的数据,按年分表,只需要查最近五年的,该怎么处理
  • 第7章:网络分析与可达性评估
  • 电子电气架构 -- bus off的机理和处理机制
  • leetcode 2536
  • OpenAI与百度同日竞速,文心5.0以原生全模态重新定义AI理解力
  • 【高级机器学习】 12. 强化学习,Q-learning, DQN
  • 网站怎么做视频的软件泰安有什么互联网公司
  • uniapp h5 app 小程序获取当前定位
  • 重庆潼南网站建设哪家好沈阳市建设工程安全监督站网站
  • [特殊字符] 嵌入式音频接口全景图解:I2S、TDM、PDM、SPDIF、AC’97 与 PCM 的关系
  • 从 API 到应用:用 Rust 和 SQLx 为 Axum 服务添加持久化数据库
  • 【高级机器学习】 9. 代理损失函数的鲁棒性
  • 测试之测试用例篇
  • 做网站优化推广的好处网站界面设计实验报告
  • 自建node云函数服务器
  • TRO侵权预警|Lauren动物插画发起维权
  • Rust实战:使用Axum和SQLx构建高性能RESTful API