C#调用Lua

目录

xLua导入

 打包工具导入

 单例基类导入与AB包管理器导入

Lua解析器

文件加载与重定向

Lua解析器管理器

全局变量获取

全局函数获取

对于无参数无返回值

 对于有参数有返回值

 对于多返回值

 对于变长参数

完整代码 

List与Dictionary映射Table

类映射Table

接口映射Table

LuaTable映射Table

xLua导入

在github上搜索xLua,选择第一个下载,进入master的Assets里面导入

 导入后可以在工具栏中看到XLua,这样导入就完成了。

 打包工具导入

这里上篇中有讲,可以看一下 https://blog.csdn.net/sara_shengxin/article/details/144596428?spm=1001.2014.3001.5502

 单例基类导入与AB包管理器导入

 获取链接http://通过网盘分享的文件:Base.rar 链接: https://pan.baidu.com/s/1-WpLVyrRFowVAs1AudrbdQ?pwd=raux 提取码: raux

AB包管理器导入,在上一篇中最终的代码复制过来就可以ABMgr

Lua解析器

 构建一个lua解析器,使得能够在unity中执行lua语言,提供的方法主要有:DoString(),Tick(),Dispose().此时调用lua脚本我们要将他放在Resources文件夹里面,且要修改lua脚本的后缀为.txt

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引入命名空间
using XLua;
public class Lesson1LuaEnv : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){//lua解析器 能够在Unity中执行lua语言LuaEnv env= new LuaEnv();//执行Lua语言env.DoString("print('nihao')");//执行一个lua脚本 ,利用lua中的多脚本执行requireenv.DoString("require('Main')");//默认脚本加载路径在resource中并且后缀为.txt//帮助清除Lua中我们没有手动清除的对象,垃圾回收//帧更新中定时执行 或者切场景的时候执行env.Tick();//销毁Lua解析器env.Dispose();}// Update is called once per framevoid Update(){}
}

 在lua的Main脚本中,我们这样写

print("主lua脚本启动")

文件加载与重定向

 上面所说的加载lua脚本的方法虽然可行,但是比较麻烦。我们还可以利用XLua中提供的一个重定向的方法AddLoader(),允许我们自定义加载lua的方法

using System.IO;
using UnityEngine;
using XLua;public class Lesson2Loader : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaEnv env = new LuaEnv();//xlua提供一个路径重定向的方法//允许我们自定义加载lua文件的规则//当我们执行lua语言 require时,相当于执行一个lua脚本//他会执行我们自定义传入的这个函数env.AddLoader(MyCustomLoader);env.DoString("require('Main')");}// Update is called once per framevoid Update(){}//自动执行private byte[] MyCustomLoader(ref string filepath){//通过函数中的逻辑加载lua文件//传入的参数是require执行lua脚本文件名//拼接一个lua文件所在的路径string path =Application.dataPath+"/LUA/"+filepath+".lua";Debug.Log(path);//有路径就去加载文件//File知识点 C#提供的文件读写的类//判断文件是否存在if(File.Exists(path)){return File.ReadAllBytes(path);}else{Debug.Log("文件不存在"+filepath);}return null;}
}

 使用require("lua脚本")的方法会先去自定义的函数里面找文件,如果找到则返回,找不到会在默认路径里面寻找

Lua解析器管理器

 有了上面的经验,我们可以创建一个lua管理器,为C#解析lua提供一些通用的方法

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Rendering.VirtualTexturing;
using XLua;
/// <summary>
/// lua管理器
/// 提供lua解析器
/// 保证解析器唯一性
/// 提供通用的方法
/// </summary>
public class LuaMgr:BaseManager<LuaMgr>
{//执行lua语言的函数//释放垃圾//重定向//销毁private LuaEnv luaenv;/// <summary>/// 得到lua中的_G/// </summary>public LuaTable Global{get{return luaenv.Global;}}/// <summary>/// 初始化/// </summary>public void Init(){if (luaenv != null)return;luaenv = new LuaEnv();//重定向luaenv.AddLoader(MyCustomLoader);luaenv.AddLoader(MyCustomLoaderAB);}//自动执行private byte[] MyCustomLoader(ref string filepath){//通过函数中的逻辑加载lua文件//传入的参数是require执行lua脚本文件名//拼接一个lua文件所在的路径string path = Application.dataPath + "/LUA/" + filepath + ".lua";//有路径就去加载文件//File知识点 C#提供的文件读写的类//判断文件是否存在if (File.Exists(path)){return File.ReadAllBytes(path);}else{Debug.Log("文件不存在" + filepath);}return null;}//Lua脚本会放在AB包中//最终我们会通过加载AB包再加载其中的Lua脚本资源来执行//AB包中如果要加载文本,后缀还是会有限制 .lua不能被识别//打包时还是要把lua文件后缀改为txt//重定向加载AB中的lua脚本private byte[] MyCustomLoaderAB(ref string filepath){Debug.Log("进入AB包加载");从AB包中加载Lua文件加载AB包//string path = Application.streamingAssetsPath + "/LUA";//AssetBundle ab=AssetBundle.LoadFromFile(path);加载Lua文件,返回//TextAsset tx = ab.LoadAsset<TextAsset>(filepath + ".lua");加载lua文件里的byte数组//return tx.bytes;//通过AB包管理器加载的lua脚本TextAsset lua =ABgr.GetInstance().LoadRes<TextAsset>("LUA", filepath + ".lua");if (lua != null){return lua.bytes;}else{Debug.Log("重定向失败"+filepath);}return null;}/// <summary>/// 传入lua文件名,执行lua脚本/// </summary>/// <param name="filename"></param>public void DoLuaFile(string filename){string s = string.Format("require('{0}')", filename);DoString(s);}/// <summary>/// 执行lua语言/// </summary>/// <param name="s"></param>public void DoString(string s){if(luaenv == null){Debug.Log("解析器未初始化");return;}luaenv.DoString(s);}/// <summary>/// 释放垃圾/// </summary>public void Tick(){if (luaenv == null){Debug.Log("解析器未初始化");return;}luaenv.Tick();}/// <summary>/// 销毁/// </summary>public void Dispose(){if (luaenv == null){Debug.Log("解析器未初始化");return;}luaenv.Dispose();luaenv= null;}}

全局变量获取

 我们修改lua中Main脚本的内容

print("主lua脚本启动")
--Unity中写lua执行
--xlua帮我们处理
--只要是执行lua脚本都会自动进入我们的重定向函数中找文件
require("Test")

然后我们在test脚本中声明一些变量,必须是全局变量,因为通过C#不能获取Lua中的本地变量

testnum=1
testbool=true
testfloat=11.8
teststring="xxxx"

 然后我们通过Global属性,利用Get获取,如果我们要修改值的内容,利用Set进行修改。如果直接修改是不能改变lua中的内容的,因为是浅拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson4CallVarlable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//使用lua解析器中的luaenv中的Global属性//获取int i=LuaMgr.GetInstance().Global.Get<int>("testnum");Debug.Log(i);//该值LuaMgr.GetInstance().Global.Set("testnum",100);int i2 = LuaMgr.GetInstance().Global.Get<int>("testnum");Debug.Log(i2);//不能获取lua中的本地局部变量//int test=LuaMgr.GetInstance().Global.Get<int>("test");//Debug.Log(test);}// Update is called once per framevoid Update(){}
}

全局函数获取

 在获取全局函数时,我们有四种类型的函数:无参数无返回值,有参数有返回值,多返回值,变长参数。

对于无参数无返回值

我们有四种方式获取:

//声明一个无参数无返回值的委托
public delegate void CallNoReturn();//start中调用CallNoReturn callNoReturn = LuaMgr.GetInstance().Global.Get<CallNoReturn>("testFun");
callNoReturn();//Unity自带的委托(无返回值)
UnityAction ua= LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");
ua();//C#的委托(无返回值)
Action action = LuaMgr.GetInstance().Global.Get<Action>("testFun");
action();//xLua 提供的一种获取函数的方式(尽量少用,会产生一些垃圾)
LuaFunction lf= LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");
lf.Call();
--无参无返回
testFun=function (  )print("无参数无返回")
end

 对于有参数有返回值

也是类似的:其中要注意的时,由于必须添加[CSharpCallLua],因此要在Xlua中先清除生成代码,再生成代码,然后再运行

/声明一个有参数有返回值的委托
//该特性是在xlua命名空间中的
[CSharpCallLua]
public delegate int CallHaveReturn(int a);//start中调用
CallHaveReturn callHaveReturn = LuaMgr.GetInstance().Global.Get<CallHaveReturn>("testFunc");
Debug.Log("有参有返回"+callHaveReturn(8));Func<int,int> func = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFunc");
Debug.Log(func(5));LuaFunction lf1 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc");
Debug.Log(lf1.Call(19)[0]);//一个返回值返回数组第0个
--有参有返回
testFunc=function ( a)print("有参数有返回值")return a+4end

 对于多返回值

我们使用out或者ref来接收,他们两个类似,区别为使用out不需要初始化,使用ref需要为他初始化

同样保存后也需要在XLua中重新生成代码再运行

我们还可以使用LuaFunction,使用数组来存他的多个返回值然后再遍历输出

//声明一个多返回值的委托 用out
[CSharpCallLua]
public delegate int CallMutReturn(int a, out int b, out bool c, out float d);//声明一个多返回值的委托 用ref
[CSharpCallLua]
public delegate int CallMutReturn1(int a, ref int b, ref bool c, ref float d);CallMutReturn callMutReturn = LuaMgr.GetInstance().Global.Get<CallMutReturn>("testFunc3");
int b;
bool c;
float d;
Debug.Log("第一个返回值" + callMutReturn(123,out b,out c,out d));
Debug.Log(b+"_"+c+"_"+d);CallMutReturn1 callMutReturn1 = LuaMgr.GetInstance().Global.Get<CallMutReturn1>("testFunc3");
int b1=0;
bool c1=false;
float d1=0.0f;
Debug.Log("第一个返回值" + callMutReturn1(100, ref b1, ref c1, ref d1));
Debug.Log(b1 + "_" + c1 + "_" + d1);//使用luaFunction
LuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc3");
object[] obj = lf2.Call(10);
for(int i = 0; i < obj.Length; i++){Debug.Log("第"+i+"个返回值是"+obj[i]);}

 对于变长参数

我们使用自定义的一个委托,变长参数我们使用params,如果能确定是同一类型,后面可以使用该类型,如果有各种类型就使用object

//声明一个变长参数的委托
[CSharpCallLua]
public delegate void CallChange(int a,params object[] obj);CallChange callChange = LuaMgr.GetInstance().Global.Get<CallChange>("testFunc4");
callChange(3,false,"jwhdkh",7.666,658);LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc4");
lf3.Call(2, false, "jwhdkh", 7.666, 658);
--变长参数
testFunc4=function ( a,... )print("变长参数")print(a)arg={...}for k,v in pairs(arg) doprint(k,v)end
end

完整代码 

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using XLua;//声明一个无参数无返回值的委托
public delegate void CallNoReturn();//声明一个有参数有返回值的委托
//该特性是在xlua命名空间中的
[CSharpCallLua]
public delegate int CallHaveReturn(int a);//声明一个多返回值的委托 用out
[CSharpCallLua]
public delegate int CallMutReturn(int a, out int b, out bool c, out float d);//声明一个多返回值的委托 用ref
[CSharpCallLua]
public delegate int CallMutReturn1(int a, ref int b, ref bool c, ref float d);//声明一个变长参数的委托
[CSharpCallLua]
public delegate void CallChange(int a,params object[] obj);//如果lua中后面的变长数组全是int或者是一种类型,那么可以就写params int[] b或者params string[] c
public class Lesson5CallFunction : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");无参无返回的获取//委托CallNoReturn callNoReturn = LuaMgr.GetInstance().Global.Get<CallNoReturn>("testFun");callNoReturn();//Unity自带的委托(无返回值)UnityAction ua= LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");ua();//C#的委托(无返回值)Action action = LuaMgr.GetInstance().Global.Get<Action>("testFun");action();//xLua 提供的一种获取函数的方式(尽量少用,会产生一些垃圾)LuaFunction lf= LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");lf.Call();//有参有返回CallHaveReturn callHaveReturn = LuaMgr.GetInstance().Global.Get<CallHaveReturn>("testFunc");Debug.Log("有参有返回"+callHaveReturn(8));Func<int,int> func = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFunc");Debug.Log(func(5));LuaFunction lf1 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc");Debug.Log(lf1.Call(19)[0]);//一个返回值返回数组第0个///多返回值//使用out与ref来接收(out接收外面的值不需要初始化,ref需要初始化)CallMutReturn callMutReturn = LuaMgr.GetInstance().Global.Get<CallMutReturn>("testFunc3");int b;bool c;float d;Debug.Log("第一个返回值" + callMutReturn(123,out b,out c,out d));Debug.Log(b+"_"+c+"_"+d);CallMutReturn1 callMutReturn1 = LuaMgr.GetInstance().Global.Get<CallMutReturn1>("testFunc3");int b1=0;bool c1=false;float d1=0.0f;Debug.Log("第一个返回值" + callMutReturn1(100, ref b1, ref c1, ref d1));Debug.Log(b1 + "_" + c1 + "_" + d1);//使用luaFunctionLuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc3");object[] obj = lf2.Call(10);for(int i = 0; i < obj.Length; i++){Debug.Log("第"+i+"个返回值是"+obj[i]);}变长参数CallChange callChange = LuaMgr.GetInstance().Global.Get<CallChange>("testFunc4");callChange(3,false,"jwhdkh",7.666,658);LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc4");lf3.Call(2, false, "jwhdkh", 7.666, 658);}}

List与Dictionary映射Table

 我们在lua中分别创建一个同类型与不同类型的列表与字典,列表一般用来没有自定义索引的表,如果确定类型就用指定类型,如果不确定就用object。字典一般是用来有自定义索引的表,如果确定类型就用指定类型,如果不确定就用object。

--List
testlist ={1,2,3,4,5,6}
testlist2={"vv",4,34,true,4.68}--Dictionary
testDic={["1"]=1,["2"]=2,["3"]=3,["4"]=4,["5"]=5
}
testDic2={["1"]=1,[true]=2,[false]=true,["4"]=4.5,["5"]=false
}

 注意:遍历列表时用for,遍历字典时我们使用的时foreach。并且无论是字典还是列表,都为浅拷贝。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson6CallListDic : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//同一类型 ListList<int> list = LuaMgr.GetInstance().Global.Get<List<int>>("testlist");Debug.Log("*********************List**********************");for(int i = 0; i < list.Count; i++){Debug.Log(list[i]);}//为值拷贝 浅拷贝,不会改变lua中的值//list[0] = 100;//List<int> list2 = LuaMgr.GetInstance().Global.Get<List<int>>("testlist");//for (int i = 0; i < list.Count; i++)//{//    Debug.Log(list2[i]);//}//不指定类型 ListList<object> list3= LuaMgr.GetInstance().Global.Get<List<object>>("testlist2");for (int i = 0; i < list3.Count; i++){Debug.Log(list3[i]);}Debug.Log("*********************Dic**********************");//同一类型 DicDictionary<string,int> dic1= LuaMgr.GetInstance().Global.Get<Dictionary<string,int>>("testDic");foreach(string item in dic1.Keys){Debug.Log(item + "_" + dic1[item]);}//若直接修改值,也为浅拷贝//不同类型 DicDictionary<object, object> dic2 = LuaMgr.GetInstance().Global.Get<Dictionary<object, object>>("testDic2");foreach (object item in dic2.Keys){Debug.Log(item + "_" + dic2[item]);}}// Update is called once per framevoid Update(){}
}

类映射Table

 lua中没有类,用表自定义类

testClass={testint=5,testbool=true,testfloat=4.5,teststring="xnbsa",testFun=function (  )print("243566764")endtestInClass={testInInt=66,testInString=("*****************这是一个嵌套表******************")}
}

 在C#中,我们也定义一个类,其中声明的成员变量名字要和lua中一致,数量可以多也可以少。类中的嵌套在C#上的表现也是再声明一个类,其中的成员变量与函数名也要相同。

其中,在类中的拷贝为深拷贝,在C#中修改值会同步修改lua中的值

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public class CallLuaClass
{//在类中声明成员变量 名字要和lua中的一样//数量可以比lua中多也可以更少public int testint;public float testfloat;public bool testbool;public string teststring;public UnityAction testFun;public CallLuaInClass testInClass;
}public class CallLuaInClass
{public int testInInt;public string testInString;
}
public class Lesson7CallClass : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");Debug.Log(obj.testint);Debug.Log(obj.testfloat);Debug.Log(obj.testbool);//Debug.Log(obj.teststring);//obj.testFun();Debug.Log(obj.testInClass.testInInt);Debug.Log(obj.testInClass.testInString);//浅拷贝//obj.testint = 999;//CallLuaClass obj1 = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");//Debug.Log(obj1.testint);}// Update is called once per framevoid Update(){}
}

接口映射Table

 lua中的脚本我们继续使用类的代码

testClass={testint=5,testbool=true,testfloat=4.5,teststring="xnbsa",testFun=function (  )print("243566764")end
}

 但是在C#中,接口是不允许有成员变量的,我们要使用属性来接收lua中的变量。

由于我们要使用[CSharpCallLua],在每一次对接口进行修改后我们都需要在XLua中进行清空然后生成代码再运行。

接口也可以有嵌套,嵌套方式与类中相似

注意的是接口中的拷贝也为深拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;[CSharpCallLua]
//接口中是不允许有成员变量,因此我们用属性来接收
//与类相似,内容属性可多可少,但是每一次修改interface结构后都需要先清空xLua再生成运行
//嵌套几乎和类一样,无非就是要遵循接口的规则
public interface ICCallLua
{int testint{get; set;}bool testbool{get; set;}float testfloat{get; set;}string teststring{get; set;}UnityAction testFun{get; set;}
}public class Lesson8CallInterface : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");ICCallLua obj = LuaMgr.GetInstance().Global.Get<ICCallLua>("testClass");Debug.Log(obj.testint);Debug.Log(obj.testbool);Debug.Log(obj.teststring);Debug.Log(obj.testfloat);obj.testFun();//接口为引用拷贝,改了值lua中的值也会变化obj.testint = 18888;ICCallLua obj1 = LuaMgr.GetInstance().Global.Get<ICCallLua>("testClass");Debug.Log(obj1.testint);}// Update is called once per framevoid Update(){}
}

LuaTable映射Table

 同样使用lua之前的代码

testClass={testint=5,testbool=true,testfloat=4.5,teststring="xnbsa",testFun=function (  )print("243566764")end
}

 在之前的使用中,我们多次用到LuaTable,在LuaMgr的定义中我们知道,他将其定义为Global,来得到Get里面的变量与函数

但是我们不建议使用LuaTable与LuaFunction,因为他们效率低且会产生垃圾,在不需要使用后要记得销毁

并且他也为深拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;public class Lesson9CallLuaTable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//不建议用LuaTable与LauFunction,因为效率低且容易产生垃圾//是一种引用对象LuaTable table=LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table.Get<int>("testint"));Debug.Log(table.Get<bool>("testbool"));Debug.Log(table.Get<float>("testfloat"));Debug.Log(table.Get<string>("teststring"));table.Get<LuaFunction>("testFun").Call();//是引用拷贝table.Set("testint", 1949);Debug.Log(table.Get<int>("testint"));LuaTable table1 = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table1.Get<int>("testint"));//不用了要记得销毁,会有垃圾table.Dispose();table1.Dispose();}// Update is called once per framevoid Update(){}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/501854.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Wend看源码-Java-fork/Join并行执行任务框架学习

摘要 本文主要介绍了Java的Fork/Join并行任务执行框架&#xff0c;详细阐述了其工作原理和核心构件&#xff0c;全面解读了Fork/Join框架的运作机制&#xff0c;旨在为学习这一框架的开发者提供一份详实且实用的参考资料。 Java的Fork/Join框架是Java 7引入的一个用于并行执行任…

C++ 中 Unicode 字符串的宽度

首先&#xff0c;什么是 Unicode&#xff1f; Unicode 实际上是一个统一的文字编码标准&#xff0c;它出现目的是为了解决不同计算机之间字符编码不同而导致的灾难性不兼容问题。 Unicode 字符集与 Unicode 编码是两种不同的概念。Unicode 字符集实际是对进入标准的所有文字用…

Python爬虫 - 豆瓣图书数据爬取、处理与存储

文章目录 前言一、使用版本二、需求分析1. 分析要爬取的内容1.1 分析要爬取的单个图书信息1.2 爬取步骤1.2.1 爬取豆瓣图书标签分类页面1.2.2 爬取分类页面1.2.3 爬取单个图书页面 1.3 内容所在的标签定位 2. 数据用途2.1 基础分析2.2 高级分析 3. 应对反爬机制的策略3.1 使用 …

MIPI_DPU 综合(DPU+MIPI+Demosaic+VDMA 通路)

目录 1. 简介 2. 创建 Platform 2.1 Block Design 2.1.1 DPU PFM Lite 2.1.2 DPU prj 2.1.3 DPU MIPI Platform 2.2 pin 约束 2.2.1 GPIO 约束 2.2.2 IIC 约束 2.1.3 DPHY 约束 3. 报错总结 3.1 AXI_M 必须顺序引用 3.2 DPU 地址分配错误 4. Design Example 4.…

Spring系列一:spring的安装与使用

文章目录 ?? 官方资料 ??Spring5下载??文档介绍 ??Spring5 ??内容介绍??重要概念 ??快速入门 ??Spring操作演示??类加载路径??Spring容器结构剖析??Debug配置 ??实现简单基于XML配置程序 ??Spring原生容器结构梳理??作业布置??Spring课堂练习 …

AutoSar架构学习笔记

1.AUTOSAR&#xff08;Automotive Open System Architecture&#xff0c;汽车开放系统架构&#xff09;是一个针对汽车行业的软件架构标准&#xff0c;旨在提升汽车电子系统的模块化、可扩展性、可重用性和互操作性。AUTOSAR的目标是为汽车电子控制单元&#xff08;ECU&#xf…

Kernel Stack栈溢出攻击及保护绕过

前言 本文介绍Linux内核的栈溢出攻击&#xff0c;和内核一些保护的绕过手法&#xff0c;通过一道内核题及其变体从浅入深一步步走进kernel世界。 QWB_2018_core 题目分析 start.sh qemu-system-x86_64 \-m 128M \-kernel ./bzImage \-initrd ./core.cpio \-append "…

【顶刊TPAMI 2025】多头编码(MHE)之Part 6:极限分类无需预处理

目录 1 标签分解方法的消融研究2 标签分解对泛化的影响3 讨论4 结论 论文&#xff1a;Multi-Head Encoding for Extreme Label Classification 作者&#xff1a;Daojun Liang, Haixia Zhang, Dongfeng Yuan and Minggao Zhang 单位&#xff1a;山东大学 代码&#xff1a;https:…

友元和运算符重载

1. 友元 可以把某些选定的函数看作类的“荣誉函数”&#xff0c;允许它们访问类对象中非公共的成员&#xff0c;就好像它们是类的成员一样&#xff0c;这种函数称为类的友元。友元可以访问类对象的任意成员。 1.1 友元函数 友元函数是一种定义在类外部的普通函数&#xff0…

Git 树形图表不显示问题

注册表修改 ## 注册表 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers 生效 右键重启 windows资源管理器

【MySQL基础篇】三、表结构的操作

文章目录 Ⅰ. 创建表1、语法2、创建表样例3、创建和其它表一样结构的表 Ⅱ. 查看表结构1、查看数据库中的表2、查看指定表的属性3、获取表的创建语句 Ⅲ. 删除表Ⅳ. 修改表结构1、向表中插入新的字段2、删除表中的字段3、修改表名4、修改字段属性 Ⅰ. 创建表 1、语法 create …

aws(学习笔记第二十二课) 复杂的lambda应用程序(python zip打包)

aws(学习笔记第二十二课) 开发复杂的lambda应用程序(python的zip包) 学习内容&#xff1a; 练习使用CloudShell开发复杂lambda应用程序(python) 1. 练习使用CloudShell CloudShell使用背景 复杂的python的lambda程序会有许多依赖的包&#xff0c;如果不提前准备好这些python的…

SAP SD销售模块常见BAPI函数

【SAP系统研究】 #SAP #SD #销售管理 1、销售订单 BAPI_SALESORDER_CREATEFROMDAT2 创建销售订单 BAPI_CUSTOMERRETURN_CREATE 创建退货订单 SD_SALESDOCUMENT_CREATE 创建贷项订单 BAPI_SALESORDER_CHANGE 修改销售订单 STATUS_READ 查看销售订单状态VB销售订单000000 I_CHA…

CSS学习记录21

CSS 工具提示 通过CSS 创建工具提示&#xff08;Tooltip)。 当用户将鼠标指针移动到元素上时&#xff0c;工具提示通常用于提供关于某内容的额外信息&#xff1a; <style> /* Tooltip 容器 */ .tooltip {position: relative;display: inline-block;border-bottom: 1px …

DuckDB:密钥管理器及其应用

密钥管理器(Secrets Manager)为所有使用密钥的后端提供了统一的用户界面。密钥信息可以被限定范围&#xff0c;因此不同的存储前缀可以有不同的密钥信息&#xff0c;例如允许在单个查询中连接跨组织的数据。密钥也可以持久化&#xff0c;这样就不需要在每次启动DuckDB时都指定它…

[cg] android studio 无法调试cpp问题

折腾了好久&#xff0c;native cpp库无法调试问题&#xff0c;原因 下面的Deploy 需要选Apk from app bundle!! 另外就是指定Debug type为Dual&#xff0c;并在Symbol Directories 指定native cpp的so路径 UE项目调试&#xff1a; 使用Android Studio调试虚幻引擎Android项目…

uni-app深度解码:跨平台APP开发的核心引擎与创新实践

在当今数字化浪潮中&#xff0c;移动应用市场呈现出爆炸式增长。为了满足不同用户群体在不同操作系统上的需求&#xff0c;跨平台 APP 开发成为众多开发者的首选策略。uni-app 作为一款领先的跨平台开发框架&#xff0c;以其独特的优势和创新的实践在众多同类产品中脱颖而出。它…

I2C(一):存储器模式:stm32作为主机对AT24C02写读数据

存储器模式&#xff1a;在HAL库中&#xff0c;I2C有专门对存储器外设设置的库函数 I2C&#xff08;一&#xff09;&#xff1a;存储器模式的使用 1、I2C轮询式写读AT24C02一页数据2、I2C轮询式写读AT24C02多页数据3、I2C中断式写读AT24C02一页数据4、I2C使用DMA式写读AT24C02一…

Elasticsearch:减少 Elastic 容器镜像中的 CVE(常见的漏洞和暴露)

作者&#xff1a;来自 Elastic Maxime Greau 在这篇博文中&#xff0c;我们将讨论如何通过在 Elastic 产品中切换到最小基础镜像并优化可扩展漏洞管理程序的工作流程来显著减少 Elastic 容器镜像中的常见漏洞和暴露 (Common Vulnerabilities and Exposures - CVEs)。 基于 Chai…

【AI学习】Transformer深入学习(二):从MHA、MQA、GQA到MLA

前面文章&#xff1a; 《Transformer深入学习&#xff08;一&#xff09;&#xff1a;Sinusoidal位置编码的精妙》 一、MHA、MQA、GQA 为了降低KV cache&#xff0c;MQA、GQA作为MHA的变体&#xff0c;很容易理解。 多头注意力&#xff08;MHA&#xff09;&#xff1a; 多头注…