协议(消息)生成
目录
协议(消息)生成主要做什么?
知识点二 制作功能前的准备工作
编辑编辑 制作消息生成功能
实现效果
总结
上一篇中配置的XML文件可见:
https://mpbeta.csdn.net/mp_blog/creation/editor/147647176
协议(消息)生成主要做什么?
//协议生成 主要是使用配置文件中读取出来的信息
//动态的生成对应语言的代码文件
//每次添加消息或者数据结构类时,我们不需要再手写代码了
//我们不仅可以生成C#脚本文件,还可以根据需求生成别的语言的文件
#endregion
知识点二 制作功能前的准备工作
//协议生成是不会在发布后使用的功能,主要是在开发时使用
//所以我们在Unity当中可以把它作为一个编辑器功能来做
//因此我们可以专门新建一个Editor文件夹 (专门放编辑器相关内容,不会发布)
//在其中放置配置文件、自动生成相关脚本文件
Unity编辑器功能代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Xml;public class ProtocolTool
{private static string PROTO_PATH = Application.dataPath + "/Editor/protocolTool/protocolInfo.xml";private static GeneratreCSharp generatreCSharp = new GeneratreCSharp();[MenuItem("ProtocolTool/生成C#脚本")]private static void GenerateCSharp(){//1.读取xml相关信息//XmlNodeList list = GetNodes("enum");//2.根据这些信息,去拼接字符串,生成对应的脚本generatreCSharp.GeneratreEnum(GetNodes("enum"));//刷新编辑器页面 让我们可以看到生成的内容 不需要手动刷新了//生成数据结构类generatreCSharp.GeneratreData(GetNodes("data"));//生成消息类generatreCSharp.GeneratreMsg(GetNodes("message"));AssetDatabase.Refresh();}[MenuItem("ProtocolTool/生成C++脚本")]private static void GenerateCpp(){Debug.Log("生成C++脚本");}[MenuItem("ProtocolTool/生成Java脚本")]private static void GenerateJava(){Debug.Log("生成Java脚本");}private static XmlNodeList GetNodes(string nodeName){XmlDocument xml = new XmlDocument();xml.Load(PROTO_PATH);XmlNode root= xml.SelectSingleNode("messages");return root.SelectNodes(nodeName);}
}


制作消息生成功能
根据配置好的XML文件来制作消息生成工具,分别实现生成枚举类型,数据结构类型(其中包括GetBytesNum,Writing,Reading函数),消息类型脚本
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEngine;public class GeneratreCSharp
{//协议保存路径private string SAVE_PATH = Application.dataPath + "/Scripts/Protocol/";//生成枚举脚本的逻辑public void GeneratreEnum(XmlNodeList nodes){string namespaceStr = "";string enumNameStr = "";string fieldStr = "";foreach (XmlNode enumNodes in nodes){//获取命名空间配置信息namespaceStr = enumNodes.Attributes["namespace"].Value;//获取枚举名配置信息enumNameStr = enumNodes.Attributes["name"].Value;//获取所有字段节点 然后进行字符串拼接XmlNodeList enumFields = enumNodes.SelectNodes("field");//一个新的枚举 需要清空一次上一次拼接的字段字符串fieldStr = "";foreach (XmlNode enumField in enumFields){fieldStr += "\t\t" + enumField.Attributes["name"].Value;if (enumField.InnerText != "")fieldStr +="="+ enumField.InnerText;fieldStr += ",\r\n";}//对所有可变的内容进行拼接string enumStr = $"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic enum {enumNameStr}\r\n" +"\t{\r\n" +$"{fieldStr}" +"\t}\r\n" +"}";//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Enum/";//如果不存在这个文件夹 则创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + enumNameStr + ".cs", enumStr);}Debug.Log("枚举生成结束");}//生成数据结构类的逻辑public void GeneratreData(XmlNodeList nodes){string namespaceStr = "";string classNameStr = "";string fieldStr = "";string GetBytesNumStr = "";string WritingStr = "";string ReadingStr = "";foreach (XmlNode dataNode in nodes){//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;//读取所有字段节点XmlNodeList fields = dataNode.SelectNodes("field");//通过这个方法进行成员变量声明的拼接 返回拼接结果fieldStr = GetFieldStr(fields);//通过这个方法对GetBytesNum函数中字符串内容进行拼接 返回结果GetBytesNumStr = GetGetBytesNumStr(fields);//通过这个方法对Writing函数中字符串内容进行拼接 返回结果WritingStr = GetWritingStr(fields);//通过这个方法对Reading函数中字符串内容进行拼接 返回结果ReadingStr = GetReadingStr(fields);string dataStr = "using System;\r\n"+"using System.Collections.Generic;\r\n" +"using System.Text;\r\n"+$"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseData\r\n" +"\t{\r\n" +$"{fieldStr}" +"\t\tpublic override int GetBytesNum()\r\n" +"\t\t{\r\n" +"\t\t\tint num=0;\r\n" +$"{GetBytesNumStr}" +"\t\t\treturn num;\r\n"+"\t\t}\r\n"+"\t\tpublic override byte[] Writing()\r\n"+"\t\t{\r\n"+"\t\t\tint index =0;\r\n"+"\t\t\tbyte [] bytes =new byte[GetBytesNum()];\r\n"+$"{WritingStr}"+"\t\t\treturn bytes;\r\n"+"\t\t}\r\n"+"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index =beginIndex ;\r\n" +$"{ReadingStr}" +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n" +"\t}\r\n" +"}";//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Data/";//如果不存在这个文件夹 则创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + classNameStr + ".cs", dataStr);}Debug.Log("数据结构类生成结束");}private string GetFieldStr(XmlNodeList fields){string fieldStr = "";foreach (XmlNode field in fields){//变量类型string type = field.Attributes["type"].Value;//变量名string fieldName = field.Attributes["name"].Value;if(type=="list"){string T = field.Attributes["T"].Value;fieldStr += "\t\tpublic List<" + T + ">";}else if(type =="array"){string data = field.Attributes["data"].Value;fieldStr += "\t\tpublic " + data + "[]";}else if(type=="dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;fieldStr += "\t\tpublic Dictionary<" + Tkey + "," + Tvalue + ">";}else if(type=="enum"){string data = field.Attributes["data"].Value;fieldStr += "\tpublic " + data + " ";}else{fieldStr += "\t\tpublic " + type + " ";}fieldStr += fieldName + ";\r\n";}return fieldStr;}private string GetGetBytesNumStr(XmlNodeList fields){string bytesNumStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;bytesNumStr += "\t\t\tnum +=2;\r\n";//+2是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tfor(int i = 0;i< " + name + ".Count;i++)\r\n";//这里使用name+"[i]"的目的是获取list当中的元素传入使用bytesNumStr += "\t\t\t\tnum +=" + GetValueBytesNum(T, name + "[i]") + ";\r\n";}else if (type == "array"){string data = field.Attributes["data"].Value;bytesNumStr += "\t\t\tnum +=2;\r\n";//+2是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tfor(int i = 0;i<" + name + ".Length;i++)\r\n";//这里使用name+"[i]"的目的是获取list当中的元素传入使用bytesNumStr += "\t\t\t\tnum +=" + GetValueBytesNum(data, name + "[i]") + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalude = field.Attributes["Tvalue"].Value;bytesNumStr += "\t\t\tnum +=2;\r\n";//+2是为了节约字节数 用一个short去存储信息bytesNumStr += "\t\t\tforeach(" + Tkey + " key in " + name + ".Keys)\r\n";bytesNumStr += "\t\t\t{\r\n";bytesNumStr += "\t\t\t\tnum +=" + GetValueBytesNum(Tkey, "key") + ";\r\n";bytesNumStr += "\t\t\t\tnum +=" + GetValueBytesNum(Tvalude, name + "[key]") + ";\r\n";bytesNumStr += "\t\t\t}\r\n";}elsebytesNumStr += "\t\t\tnum +=" + GetValueBytesNum(type, name)+";\r\n";}return bytesNumStr;}private string GetValueBytesNum(string type,string name){switch (type){case "int":case "float":case "enum":return "4";case "long":return "8";case "byte":case "bool":return "1";case "short":return "2";case "string":return "4+Encoding.UTF8.GetByteCount(" + name + ")";default:return name + ".GetBytesNum()";}}private string GetWritingStr(XmlNodeList fields){string writingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if(type=="list"){string T = field.Attributes["T"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Count, ref index);\r\n";writingStr += "\t\t\tfor (int i=0; i < " + name + ".Count;++i)\r\n";writingStr += "\t\t\t\t" + GetWritingValueStr(T, name + "[i]") + "\r\n";}else if(type=="array"){string data = field.Attributes["data"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Length, ref index);\r\n";writingStr += "\t\t\tfor (int i=0; i < " + name + ".Length;++i)\r\n";writingStr += "\t\t\t\t" + GetWritingValueStr(data, name + "[i]") + "\r\n";}else if(type=="dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Count, ref index);\r\n";writingStr += "\t\t\tforeach(" + Tkey + " key in " + name + ".Keys)\r\n";writingStr += "\t\t\t{\r\n";writingStr += "\t\t\t\t" + GetWritingValueStr(Tkey, "key") + "\r\n";writingStr += "\t\t\t\t" + GetWritingValueStr(Tvalue, name + "[key]") + "\r\n";writingStr += "\t\t\t}\r\n";}else{writingStr += "\t\t\t" + GetWritingValueStr(type, name) + "\r\n";}}return writingStr;}private string GetWritingValueStr(string type,string name){switch (type){case "byte":return "WriteByte(bytes ," + name + ", ref index);";case "int":return "WriteInt(bytes ," + name + ", ref index);";case "bool":return "WriteBool(bytes ," + name + ", ref index);";case "short":return "WriteShort(bytes ," + name + ", ref index);";case "long":return "WriteLong(bytes ," + name + ", ref index);";case "float":return "WriteFloat(bytes ," + name + ", ref index);";case "string":return "WriteString(bytes ," + name + ", ref index);";case "enum":return "WriteInt(bytes ,Convert.ToInt32(" + name + "), ref index);";default:return "WriteData(bytes ," + name + ", ref index);";}}private string GetReadingStr(XmlNodeList fields){string readingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;readingStr += "\t\t\t" + name + " =new List<" + T + ">();\r\n";readingStr += "\t\t\tshort " + name + "Count =ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\tfor (int i = 0; i < " + name + "Count; ++i)\r\n";readingStr += "\t\t\t\t" + name + ".Add(" + GetReadingValueStr(T) + ");\r\n";}else if (type == "array"){string data = field.Attributes["data"].Value;readingStr += "\t\t\tshort " + name + "Length =ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\t" + name + " = new " + data + "[" + name + "Length];\r\n";readingStr += "\t\t\tfor (int i = 0; i < " + name + "Length; ++i)\r\n";readingStr += "\t\t\t\t" + name + "[i]" +" = "+ GetReadingValueStr(data) + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;readingStr += "\t\t\t" + name + " = new Dictionary<" + Tkey + ", " + Tvalue + ">();\r\n";readingStr += "\t\t\tshort " + name + "Count =ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\tfor (int i = 0; i < " + name + "Count; ++i)\r\n";readingStr += "\t\t\t\t" + name + ".Add(" + GetReadingValueStr(Tkey) + ", " +GetReadingValueStr(Tvalue) + ");\r\n";}else if(type=="enum"){string data = field.Attributes["data"].Value;readingStr += "\t\t\t" + name + " = (" + data + ")ReadInt(bytes, ref index);\r\n";}elsereadingStr += "\t\t\t" + name + " = " + GetReadingValueStr(type) + ";\r\n";}return readingStr;}private string GetReadingValueStr(string type){switch (type){case "byte":return "ReadByte(bytes, ref index)";case "int":return "ReadInt(bytes, ref index)";case "short":return "ReadShort(bytes, ref index)";case "long":return "ReadLong(bytes, ref index)";case "float":return "ReadFloat(bytes, ref index)";case "bool":return "ReadBool(bytes, ref index)";case "string":return "ReadString(bytes, ref index)";default:return "ReadData<" + type + ">(bytes, ref index)";}}public void GeneratreMsg(XmlNodeList nodes){string idStr = "";string namespaceStr = "";string classNameStr = "";string fieldStr = "";string GetBytesNumStr = "";string WritingStr = "";string ReadingStr = "";foreach (XmlNode dataNode in nodes){//消息IDidStr = dataNode.Attributes["id"].Value;//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;//读取所有字段节点XmlNodeList fields = dataNode.SelectNodes("field");//通过这个方法进行成员变量声明的拼接 返回拼接结果fieldStr = GetFieldStr(fields);//通过这个方法对GetBytesNum函数中字符串内容进行拼接 返回结果GetBytesNumStr = GetGetBytesNumStr(fields);//通过这个方法对Writing函数中字符串内容进行拼接 返回结果WritingStr = GetWritingStr(fields);//通过这个方法对Reading函数中字符串内容进行拼接 返回结果ReadingStr = GetReadingStr(fields);string dataStr = "using System;\r\n" +"using System.Collections.Generic;\r\n" +"using System.Text;\r\n" +$"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseMsg\r\n" +"\t{\r\n" +$"{fieldStr}" +"\t\tpublic override int GetBytesNum()\r\n" +"\t\t{\r\n" +"\t\t\tint num=8;\r\n" +//这个8代表的是 消息ID的4个字节和消息长度的4个字节$"{GetBytesNumStr}" +"\t\t\treturn num;\r\n" +"\t\t}\r\n" +"\t\tpublic override byte[] Writing()\r\n" +"\t\t{\r\n" +"\t\t\tint index =0;\r\n" +"\t\t\tbyte [] bytes =new byte[GetBytesNum()];\r\n" +"\t\t\tWriteInt(bytes, GetID(), ref index);\r\n" +"\t\t\tWriteInt(bytes, bytes.Length - 8, ref index);\r\n" +$"{WritingStr}" +"\t\t\treturn bytes;\r\n" +"\t\t}\r\n" +"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index =beginIndex ;\r\n" +$"{ReadingStr}" +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n" +"\t\tpublic override int GetID()\r\n" +"\t\t{\r\n" +"\t\t\treturn " + idStr + ";\r\n"+"\t\t}\r\n" +"\t}\r\n" +"}";//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Msg/";//如果不存在这个文件夹 则创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为枚举脚本文件File.WriteAllText(path + classNameStr + ".cs", dataStr);}Debug.Log("数据结构类生成结束");}
}
实现效果
点击生成C#脚本,就会在Unity编辑器中生成一个Protocol文件夹,里边有我们想要的消息脚本
以GamePlayer命名空间为例展示生成后的代码
这是Data文件夹脚本
using System;
using System.Collections.Generic;
using System.Text;
namespace GamePlayer
{public class PlayerData : BaseData{public int id;public float atk;public bool sex;public long lev;public int[]arrays;public List<int>list;public Dictionary<int,string>dic;public override int GetBytesNum(){int num=0;num +=4;num +=4;num +=1;num +=8;num +=2;for(int i = 0;i<arrays.Length;i++)num +=4;num +=2;for(int i = 0;i< list.Count;i++)num +=4;num +=2;foreach(int key in dic.Keys){num +=4;num +=4+Encoding.UTF8.GetByteCount(dic[key]);}return num;}public override byte[] Writing(){int index =0;byte [] bytes =new byte[GetBytesNum()];WriteInt(bytes ,id, ref index);WriteFloat(bytes ,atk, ref index);WriteBool(bytes ,sex, ref index);WriteLong(bytes ,lev, ref index);WriteShort(bytes, (short)arrays.Length, ref index);for (int i=0; i < arrays.Length;++i)WriteInt(bytes ,arrays[i], ref index);WriteShort(bytes, (short)list.Count, ref index);for (int i=0; i < list.Count;++i)WriteInt(bytes ,list[i], ref index);WriteShort(bytes, (short)dic.Count, ref index);foreach(int key in dic.Keys){WriteInt(bytes ,key, ref index);WriteString(bytes ,dic[key], ref index);}return bytes;}public override int Reading(byte[] bytes, int beginIndex = 0){int index =beginIndex ;id = ReadInt(bytes, ref index);atk = ReadFloat(bytes, ref index);sex = ReadBool(bytes, ref index);lev = ReadLong(bytes, ref index);short arraysLength =ReadShort(bytes, ref index);arrays = new int[arraysLength];for (int i = 0; i < arraysLength; ++i)arrays[i] = ReadInt(bytes, ref index);list =new List<int>();short listCount =ReadShort(bytes, ref index);for (int i = 0; i < listCount; ++i)list.Add(ReadInt(bytes, ref index));dic = new Dictionary<int, string>();short dicCount =ReadShort(bytes, ref index);for (int i = 0; i < dicCount; ++i)dic.Add(ReadInt(bytes, ref index), ReadString(bytes, ref index));return index - beginIndex;}}
}
这是Enum文件夹中脚本
namespace GamePlayer
{public enum E_PLAYER_TYPE{MAIN=1,OTHER,}
}
这是Msg文件夹中脚本
using System;
using System.Collections.Generic;
using System.Text;
namespace GamePlayer
{public class PlayerMsg : BaseMsg{public int playerID;public PlayerData data;public override int GetBytesNum(){int num=8;num +=4;num +=data.GetBytesNum();return num;}public override byte[] Writing(){int index =0;byte [] bytes =new byte[GetBytesNum()];WriteInt(bytes, GetID(), ref index);WriteInt(bytes, bytes.Length - 8, ref index);WriteInt(bytes ,playerID, ref index);WriteData(bytes ,data, ref index);return bytes;}public override int Reading(byte[] bytes, int beginIndex = 0){int index =beginIndex ;playerID = ReadInt(bytes, ref index);data = ReadData<PlayerData>(bytes, ref index);return index - beginIndex;}public override int GetID(){return 1001;}}
}
总结
// 根据配置生成脚本的文件的主要思路就是
// 按规则拼接字符串
// 只要有数据和规则,我们就可以动态的创建脚本文件
相关文章:

协议(消息)生成
目录 协议(消息)生成主要做什么? 知识点二 制作功能前的准备工作 编辑编辑 制作消息生成功能 实现效果 总结 上一篇中配置的XML文件可见: https://mpbeta.csdn.net/mp_blog/creation/editor/147647176 协议(消息)生成主要做什么? //协议生成 主要是…...
SEMI E40-0200 STANDARD FOR PROCESSING MANAGEMENT(加工管理标准)-(一)
1 目的 物料(例如晶圆)加工在设备中的自动化管理与控制是实现工厂自动化的关键要素。本标准针对半导体制造环境中与设备内部物料处理相关的通信需求进行了规范。本标准规定了在加工单元接收到的指定材料所应适用的加工方法(例如Etch腔室需要Run哪支Recipe)。它阐述了物料加工的…...
Nginx1.26.2安装包编译安装并配置stream模块
准备nginx安装文件:nginx-1.26.2.tar.gz cd /usr/local wget http://nginx.org/download/nginx-1.26.2.tar.gz tar -zxvf nginx-1.26.2.tar.gz && cd nginx-1.26.2 1.创建安装目录 mkdir nginx 2.解压安装文件nginx-1.26.2.tar.gz tar -zxvf nginx-1.26…...

Linux 系统的指令详解介绍
Linux 系统的指令详解介绍 一、指令的本质与定义1. 什么是指令?2. Linux 指令分类二、指令格式解析1. 基础语法结构2. 语法要素详解(1)选项类型(2)参数类型三、核心指令分类1. 文件操作指令2. 文本处理指令3. 系统管理指令一、指令的本质与定义 1. 什么是指令? 定义:在…...

Milvus(17):向量索引、FLAT、IVF_FLAT
1 索引向量字段 利用存储在索引文件中的元数据,Milvus 以专门的结构组织数据,便于在搜索或查询过程中快速检索所需的信息。 Milvus 提供多种索引类型和指标,可对字段值进行排序,以实现高效的相似性搜索。下表列出了不同向量字段类…...

芯片笔记 - 手册参数注释
芯片手册参数注释 基础参数外围设备USB OTG(On-The-Go)以太网存储卡(SD)SDIO 3.0(Secure Digital Input/Output)GPIO(General Purpose Input/Output 通用输入/输出接口)ADC(Analog to Digital C…...
不同大模型对提示词和问题的符号标识
不同大模型对提示词和问题的符号标识 不同大模型对提示词和问题的符号标识存在差异,花括号{}在特定场景下可以使用,但需结合模型特性和上下文。 一、主流模型的符号标识惯例 1. Claude(Anthropic) 推荐符号:XML标签(如<tag>内容</tag>)。 示例:<text…...

RabbitMQ学习(第二天)
文章目录 1、生产者可靠性①、生产者重连②、生产者确认 2、MQ可靠性①、数据持久化②、LazyQueue(惰性队列) 3、消费者可靠性①、消费者确认②、失败重试机制③、保证业务幂等性 总结 之前的学习中,熟悉了java中搭建和操作RabbitMQ发送接收消息,熟悉使用…...

【JS逆向基础】爬虫核心模块:request模块与包的概念
前言:这篇文章主要介绍JS逆向爬虫中最常用的request模块,然后引出一系列的模块的概念,当然Python中其他比较常用的还有很多模块,正是这些模块也可以称之为库的东西构成了Python强大的生态,使其几乎可以实现任何功能。下…...

LabVIEW燃气轮机测控系统
在能源需求不断增长以及生态环境保护备受重视的背景下,微型燃气轮机凭借其在经济性、可靠性、维护性及排放性等方面的显著优势,在航空航天、分布式发电等众多领域得到广泛应用。随着计算机技术的快速发展,虚拟仪器应运而生,LabVIE…...
【链表扫盲】FROM GPT
链表是一种线性数据结构,由节点(Node)组成,每个节点包含两个部分: 数据域(data): 存储节点值。指针域(next): 存储指向下一个节点的引用。 链表…...

QT | 常用控件
前言 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见📝 🎉欢迎大家点赞👍收藏⭐文章 —…...
Python学习之路(八)-多线程和多进程浅析
在 Python 中,多线程(Multithreading) 和 多进程(Multiprocessing) 是实现并发编程的两种主要方式。它们各有优劣,适用于不同的场景。 一、基本概念 特性多线程(threading)多进程(multiprocessing)并发模型线程共享内存空间每个进程拥有独立内存空间GIL(全局解释器锁…...
搭建和优化CI/CD流水线
CI/CD(持续集成 / 持续交付)流水线是现代软件开发中的关键实践,它能够自动化软件的构建、测试和部署过程,提高开发效率和软件质量。以下为你介绍搭建和优化 CI/CD 流水线的详细步骤: 搭建 CI/CD 流水线 1. 选择合适的…...
kotlin 01flow-StateFlow 完整教程
一 Android StateFlow 完整教程:从入门到实战 StateFlow 是 Kotlin 协程库中用于状态管理的响应式流,特别适合在 Android 应用开发中管理 UI 状态。本教程将带全面了解 StateFlow 的使用方法。 1. StateFlow 基础概念 1.1 什么是 StateFlow? StateF…...
1.2.1 Linux音频系统发展历程简介
Linux音频系统的发展经历了从最初的简单驱动到今天多层次、模块化音频架构。简要梳理其主要历程: 早期的OSS(Open Sound System) 在90年代及2000年代初,Linux主要使用OSS来支持音频。OSS直接为硬件设备(如声卡&#…...
浏览器刷新结束页面事件,调结束事件的接口(vue)
浏览器刷新的时候,正在进行中的事件结束掉,在刷新浏览器的时候做一些操作。 如果是调接口,就不能使用axios封装的接口,需要使用原生的fetch。 找到公共的文件App.vue 使用window.addEventListener(‘beforeunload’, function (e…...
聊聊Spring AI Alibaba的SentenceSplitter
序 本文主要研究一下Spring AI Alibaba的SentenceSplitter SentenceSplitter spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/transformer/splitter/SentenceSplitter.java public class SentenceSplitter extends TextSplitter {private final EncodingRegis…...
前端-什么是结构语言、样式语言、脚本语言?
目录 1. 结构语言(HTML / WXML)——房子的骨架 2. 样式语言(CSS / WXSS)——房子的装修 3. 脚本语言(JavaScript)——房子的智能控制系统 总结对比表: 1. 结构语言(HTML / WXML&a…...

LLM论文笔记 28: Universal length generalization with Turing Programs
Arxiv日期:2024.10.4机构:Harvard University 关键词 图灵机 CoT 长度泛化 核心结论 Turing Programs 的提出 提出 Turing Programs,一种基于图灵机计算步骤的通用 CoT 策略。通过将算法任务分解为逐步的“磁带更新”(类似图灵…...

AI日报 · 2025年5月07日|谷歌发布 Gemini 2.5 Pro 预览版 (I/O 版本),大幅提升编码与视频理解能力
1、谷歌发布 Gemini 2.5 Pro 预览版 (I/O 版本),大幅提升编码与视频理解能力 谷歌于5月6日提前发布 Gemini 2.5 Pro 预览版 (I/O 版本),为开发者带来更强编码能力,尤其优化了前端与UI开发、代码转换及智能体工作流构建,并在WebDe…...

指定Docker镜像源,使用阿里云加速异常解决
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo异常贴图 yum-config-manager:找不到命令 因为系统默认没有安装这个命令,这个命令在yum-utils 包里,可以通过命令yum -y install yum-util…...

VITA STANDARDS LIST,VITA 标准清单下载
VITA STANDARDS LIST,VITA 标准清单下载 DesignationTitleAbstractStatusVMEbus Handbook, 4th EditionA users guide to the VME, VME64 and VME64x bus specifications - features over 70 product photos and over 160 circuit diagrams, tables and graphs. The…...

Python从入门到高手8.3节-元组的常用操作方法
目录 11.3.1 元组的常用操作方法 11.3.2 元组的查找 11.3.3 祈祷明天不再打雷下雨 11.3.1 元组的常用操作方法 元组类型是一种抽象数据类型,抽象数据类型定义了数据类型的操作方法,在本节的内容中,着重介绍元组类型的操作方法。 元组是…...

Linux系统安装PaddleDetection
一、安装cuda 1. 查看设备 先输入nvidia-smi,查看设备支持的最大cuda版本,选择官网中支持的cuda版本 https://www.paddlepaddle.org.cn/install/quick?docurl/documentation/docs/zh/install/conda/linux-conda.html 2. 下载CUDA并安装 使用快捷键…...
【漫话机器学习系列】239.训练错误率(Training Error Rate)
机器学习基础概念 | 训练错误率(Training Error Rate)详解 在机器学习模型训练过程中,评估模型性能是至关重要的一个环节。其中,训练错误率(Training Error Rate) 是最基础也最重要的性能指标之一。 本文将…...
Vue3路由模式为history,使用nginx部署上线是空白的问题
一、问题 将vue使用打包后 npm run build将dist文件的内容,放入nginx的html中,并在nginx.conf中,设置端口 启动nginx,打开发现网页内容为空白 二、解决问题 1.配置vue-route const router createRouter({history: createWe…...
Python 数据智能实战 (13):AI的安全可靠 - 电商数据智能的红线与指南
写在前面 —— 技术向善,行稳致远:在智能时代,坚守数据伦理,构建可信赖的 AI 应用 通过前面的篇章,我们已经深入探索了如何利用 Python 和大语言模型 (LLM) 挖掘电商数据的巨大潜力,从智能用户分群到语义推荐,再到个性化内容生成和模型效果评估。我们手中的工具越来越…...

OpenCV 图形API(80)图像与通道拼接函数-----仿射变换函数warpAffine()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 对图像应用仿射变换。 函数 warpAffine 使用指定的矩阵对源图像进行变换: dst ( x , y ) src ( M 11 x M 12 y M 13 , M 21 x M…...

数据结构与算法:图论——最短路径
最短路径 先给出一些leetcode算法题,以后遇见了相关题目再往上增加 最短路径的4个常用算法是Floyd、Bellman-Ford、SPFA、Dijkstra。不同应用场景下,应有选择地使用它们: 图的规模小,用Floyd。若边的权值有负数,需要…...