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

【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)

目录

一、前言

二、什么是C++模板? 

💦泛型编程的思想  

💦C++模板的分类 

三、非类型模板参数

⚡问题引入⚡   

⚡非类型模板参数的使用⚡    

🔥非类型模板参数的定义

🔥非类型模板参数的两种类型

🔥非类型模板参数的使用规则

⚡问题的解决⚡   

⚡非类型模板参数的实例应用⚡    

四、模板的特化 

💧 概念

💧 函数模板特化 

💧 类模板特化 

🔥全特化🔥

🔥偏特化🔥 

💧模板特化的应用示例 

五、总结 

六、共勉 


一、前言

       在我们学习C++时,常会用到函数重载。而函数重载,通常会需要我们编写较为重复的代码,这就显得臃肿,且效率低下重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数。此外,代码的可维护性比较低,一个出错可能会导致所有的重载均出错。

       那么,模板的出现,就让这些问题有了解决方案,在之前的文章中已经详细的讲解了C++的 ----- 模板初阶,所以本次博客将为大家详细的讲解C++的模板进阶!!

二、什么是C++模板? 

        程序设计中经常会用到一些程序实体它们的实现和所完成的功能基本相同不同的仅 仅是所涉及的数据类型不同而模板正是一种专门处理不同数据类型的机制


       模板------是泛型程序设计的基础(泛型generic type——通用类型之意)
 

        函数、类以及类继承为程序的代码复用提供了基本手段,还有一种代码复用途径——类属类型(泛型)利用它可以给一段代码设置一些取值为类型的参数(注意:这些参数 的值是类型,而不是某类型的数据),通过给这些参数提供一些类型来得到针对不同类 型的代码。

💦泛型编程的思想  

  首先我们来看一下下面这三个函数,如果学习过了C++函数重载 和 C++引用 的话,就可以知道下面这三个函数是可以共存的,而且传值会很方便 

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

但是真的很方便吗?这里只有三种类型的数据需要交换,若是我们需要增加交换的数据呢?再CV然后写一个函数吗?
这肯定是不现实的,所以很明显函数重载虽然可以实现,但是有一下几个不好的地方: 

  • 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  • 代码的可维护性比较低,一个出错可能所有的重载均出错

那是否能做到这么一点,告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 


 ⭐总结: 

        所以,总结上面的这么一个技术,C++的祖师爷呢就想到了【模版】这个东西,告诉编译器一个模子,然后其余的工作交给它来完成,根据不同的需求生成不同的代码 

 这就是👉泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础


💦C++模板的分类 

1️⃣: 函数模板(function tempalte):使用泛型参数的函数(function with generic parameters)
2️⃣:类模板(class template):使用泛型参数的类(class with generic parameters) 

更加具体 模板初阶知识 大家这一去看看之前的文章 ----- 模板初阶

本篇文章主要讲解 模板的高阶操作:非类型模板参数、全特化、偏特化等,以及关于模板声明与定义不能分离(在两个不同的文件中)的问题。


三、非类型模板参数

     之前所使用的模板参数都是用来匹配不同的类型,如 intdoubleDate 等,模板参数除了可以匹配类型外,还可以匹配常量(非类型),完成如数组、位图等结构的大小确定 

⚡问题引入⚡   


 问题: 

        假设我现在自定义了一个静态栈,栈的大小设置为100。然后我构建了一个int 的类型的栈st1,和一个double 类型的栈st2。那么我希望stl 的大小为100,st2 的大小为500,能不能实现呢?

 --------------  肯定是不能的! ! !


 如下面这个例子所示: 

#define N 100// 静态栈
template<class T>
class Stack
{
private:int _a[N];int _top;
};int main()
{Stack<int> st1;Stack<double> st1;return 0;
}

  • 从上图 可以发现,栈 的两个对象 的大小都为 100。 

 那有什么办法 可以解决这个问题呢?

这个时候,就要引出 ---- 非类型模板参数 


⚡非类型模板参数的使用⚡    

 我们知道模板参数分为 : 类型形参非类型形参 

  • 类型模板形参 : 出现在模板参数列表中,跟在 class 或者 typename 类之后的参数类型名称。
template <class T>  // T 为模板参数中的 ---------- 类型模板形参
  • 非类型模板形参 : 就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
template <size_t N>  // N 为模板参数中的 ------- 非类型模板形参

🔥非类型模板参数的定义

在定义模板参数时,可以不再使用 class 或 typename,而是直接使用具体的类型,如 size_t,此时称为 非类型模板参数 

注:非类型模板参数必须为常量,即在编译阶段确定值 


🔥非类型模板参数的两种类型

1️⃣: 利用 非类型模板参数 定义一个大小可以自由调整的 整型数组 类 

template<size_t N>
class arr
{
public:T& operator[](size_t pos){assert(pos >= 0 && pos < N);return _arr[pos];}size_t size() const{return N;}private:int _arr[N];	//创建大小为 N 的整型数组
};int main()
{arr<10> a1;   // 大小为 10arr<20> a2;   // 大小为 20arr<100> a3;  // 大小为 100cout << "a1.size(): " << a1.size() << endl;cout << "a2.size(): " << a2.size() << endl;cout << "a3.size(): " << a3.size() << endl;
}


2️⃣:可以再加入一个模板参数:类型,此时就可以得到一个 泛型、大小可自定义 的数组 

template<class T, size_t N>
class arr
{
public:T& operator[](size_t pos){assert(pos >= 0 && pos < N);return _arr[pos];}size_t size() const{return N;}private:int _arr[N];	//创建大小为 N 的整型数组
};int main()
{arr<int , 10> a1;   // 大小为 10arr<double , 20> a2;   // 大小为 20arr<char , 100> a3;  // 大小为 100// 输出它们的 类型cout << typeid(a1).name() << endl;cout << typeid(a2).name() << endl;cout << typeid(a3).name() << endl;
}


非类型模板参数支持缺省,因此写成这样也是合法的 

template<class T, size_t N = 10>	//缺省大小为10

🔥非类型模板参数的使用规则

 非类型模板参数要求类型为 整型家族,其他类型是不行的

  • 比如下面这些 非类型模板参数 都是标准之内的 
//整型家族(部分)
template<class T, int N>
class arr1 { /*……*/ };template<class T, long N>
class arr2 { /*……*/ };template<class T, char N>
class arr3 { /*……*/ };
  • 而一旦使用其他家族类型作为 非类型模板参数,就会引发报错 
//浮点型,非标准
template<class T, double N>
class arr4 { /*……*/ };


 因此可以总结出,非类型模板参数 的使用要求为

  • 只能将 整型家族 类型作为非类型模板参数,其他类型不在标准之内
  • 非类型模板参数必须为常量(不可被修改),且需要在编译阶段确定结果

整型家族:charshortboolintlonglong long 等


⚡问题的解决⚡   

      此时我们已经知道的非类型模板参数的用法,只需要给上面的栈添加非类型模板参数,这样就实现了 st1st2 构造不同的大小。

// 静态栈
template<class T, size_t N>
class Stack
{
private:int _a[N];int _top;
};int main()
{Stack<int, 100> st1;Stack<double, 500> st2;return 0;
}


⚡非类型模板参数的实例应用⚡    

在 C++11 标准中,引入了一个新容器 array,它就使用了 非类型模板参数,为一个真正意义上的 泛型数组,这个数组是用来对标传统数组的 

array 的第二个模板参数就是 非类型模板参数 

#include <iostream>
#include <cassert>
#include <array>using namespace std;int main()
{int arrOld[10] = { 0 };	//传统数组array<int, 10> arrNew;	//新标准中的数组//与传统数组一样,新数组并没有进行初始化//新数组对于越界读、写检查更为严格arrOld[15];	//老数组越界读,未报错arrNew[15];	//新数组则会报错arrOld[12] = 0;	//老数组越界写,不报错,出现严重的内存问题arrNew[12] = 10;	//新数组严格检查return 0;
}

array 是泛型编程思想中的产物,支持了许多 STL 容器的功能,比如 迭代器 和 运算符重载 等实用功能,最主要的改进是 严格检查越界行为 

实际开发中,很少使用 array,因为它对标传统数组,连初始化都没有,vector 在功能和实用性上可以全面碾压,并且 array 使用的是 栈区 上的空间,存在栈溢出问题,可以说 array 是一个鸡肋的容器 


四、模板的特化 

💧 概念

通常情况下,模板可以帮我们实现一些与类型无关的代码,但在某些场景中,【泛型】无法满足调用方的精准需求,此时会引发错误。

  • 比如使用 日期类 ,实现一个专门用来进行小于比较的函数模板
// 日期类
class Date
{//友元函数friend std::ostream& operator<<(std::ostream& out, const Date& d); // 标准流输出 --> printffriend std::istream& operator>>(std::istream& in, Date& d); // 标准流插入 --> scanfpublic:// 构造函数Date(int year = 1970,int month = 1,int day = 1):_year(year),_month(month),_day(day){}// 运算符重载bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}// 打印日期void Printf(){cout << _year << " / " << _month << " / " << _day << endl;}
private:int _year;int _month;int _day;
};
// 流插入
std::ostream& operator<<(std::ostream& out, const Date& d) {out << d._year << "-" << d._month << "-" << d._day << endl;return out;
}// 流提取
std::istream& operator>>(std::istream& in, Date& d) {in >> d._year >> d._month >> d._day;return in;
}// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}int main()
{cout << Less(1, 2) << endl;Date d1(2024, 7, 6);Date d2(2024, 7, 8);cout << Less(d1, d2) << endl;return 0;
}
  • 可以看到,不管是内置类型,还是自己实现的日期类,都可以通过Less函数模板来比较大小,而且结果都是正确的 

  • 那如果我们要比较指针类型呢? 
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}int main()
{Date* p1 = new Date(2024, 7, 6);Date* p2 = new Date(2024, 7, 8);cout << Less(p1, p2) << endl; return 0;
}
  • 我们运行发现,结果是正确滴呀,6 确实小于 8 哦! 

  • 如果我们再运行一次,可以看到,竟然变成了 0 了,也就是说 6 小于 8 为 false !!

  •  也就是说,Less 绝对多数情况下都可以正常比较,但是在特殊场景下就得到错误的结果

上述示例中,p1 指向的对象显然小于p2指向的对象但是Less 内部并没有比较p1和p2指向的对象内容,而比较的是pl和p2指针地址,这就无法达到预期,而错误。 

此时,就需要对 -------------- 模板进行特化处理

即 : 在原模板类的基础上 , 针对特殊类型所进行特殊化的实现方式。

模板特化中分为 函数模板特化 类模板特化。 


💧 函数模板特化 

 函数模板的特化步骤:

  • 必须要先有一个基础的函数模板
  • 关键字 template 后面接 一对空的尖括号<>
  • 『函数名后跟一对尖括号』,尖括号中指定需要特化的类型
  • 函数形参表:必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一 些奇怪的错误。

 代码示例

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{return *left < *right;
}int main()
{Date* p1 = new Date(2024, 7, 6);Date* p2 = new Date(2024, 7, 8);cout << Less(p1, p2) << endl;Date* p3 = new Date(2024, 7, 8);Date* p4 = new Date(2022, 7, 6);cout << Less(p3, p4) << endl;return 0;
}
  •  此时,就会调用特化之后的版本,而不走模板生成得啦!

注意:般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给 

bool Less(Date* left, Date* right)
{return *left < *right;
}

该种实现简单明了,代码的可读性高,容易泻。因为对于一些参数类型复 杂的函数模板,特化时才会特别给出,因此函数模板不建议特 


💧 类模板特化 

       模板特化主要用在 --- 类模板,它可以在泛型思想之上解决大部分特殊问题,并且类模板特化还可以分为:全特化偏特化适用于不同场景

🔥全特化🔥

全特化指 将所有的模板参数特化为具体类型,将模板全特化后,调用时,会优先选择更为匹配的模板类。
简单一点来说:全特化 就是将模板参数列表中 所有的参数都确定话

全特化的特化步骤: 

  • 首先必须要有一个基础的类模板 
  • 关键字template后接一对空的尖括号<>
  • 『类名后跟一对尖括号』,尖括号中指定需要特化的类型

 假设有下面这样一个 Data 类,我希望 构造函数 打印出来的 d2 对象里面 Tl int T2 是 double,有什么办法吗?

template<class T1, class T2>
class Data
{
public:Data(){cout << "Data<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};int main()
{Data<int, int> d1;Data<int, double> d2;return 0;
}

我们实例化 dl d2 对象时,编译器会自动调用其默认构造函数,当我们打印的时候,可以看到实际上d2 对象里面还是 T1T2  并不是我们想要的 int double。  

那么这个时候 ,我们就可以对 T1T2 进行模板的特化

template<class T1, class T2>
class Data
{
public:Data(){cout << "Data<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};// 全特化
template<>
class Data<int, double>
{
public:Data(){cout << "Data<int, double>" << endl;}
private:int _d1;double _d2;
};int main()
{Data<int, int> d1;Data<int, double> d2;return 0;
}

当我们运行以后,可以看到 d2 对象就去调用刚刚写好的特化类模板 


 总结: 

对模板进行全特化处理后,实际调用时,会优先选择已经特化并且类型符合的模板这就好比虽然你家冰箱里有菜,但你还是想点外卖,因为外卖对于你来说更加合适 


🔥偏特化🔥 

偏特化是指任何针对模板参数进一步进行条件限制设计的特化版本。

偏特化又可分为以下两种表现形式:『 部分特化』、『 参数更进一步的限制』

偏特化的特化步骤: 

  • 首先必须要有一个基础的类模板 
  • 关键字template后接一对尖括号,尖括号中指定特定类型
  • 『类名后跟一对尖括号』,尖括号中指定需要特化的类型

『 部分特化』: 

将模板参数类表中的一部分参数特化。 

比如我们对 Tl 类型进行特化处理,固定其类型为 double 

template<class T1, class T2>
class Data
{
public:Data(){cout << "Data<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};// 部分特化 -- 将第一个参数特化为double
template<class T2>
class Data<double, T2>
{
public:Data(){cout << "Data<double, T2>" << endl;}
private:double _d1;T2 _d2;
};int main()
{Data<int, int> _d1;Data<double, double> _d2;Data<double, char> _d3;return 0;
}

 可以看到,当我们指定T1 为 double 的时候,才会调用这个部分特化的类模板。


 『 参数更进一步的限制』

偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限 制所设计出来的一个特化版本。 

// 基础模板
template<class T1, class T2>
class Data
{
public:Data(){cout << "Data<T1, T2>" << endl;}
private:T1 _d1;T2 _d2;
};// 部分特化 -- 将第一个参数特化为double
template<class T2>
class Data<double, T2>
{
public:Data(){cout << "Data<double, T2>" << endl;}
private:double _d1;T2 _d2;
};//两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:Data() { cout << "Data<T1*, T2*>" << endl; }private:T1 _d1;T2 _d2;
};//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout << "Data<T1&, T2&>" << endl;}private:const T1& _d1;const T2& _d2;
};// 主函数
int main()
{Data<int, int> d1; // 调用基础的版本Data<double, double> d2; // 调用部分特化的double版本Data<int*, int*> d3; // 调用特化的指针版本Data<int&, int&> d4(2, 4); // 调用特化的引用版本return 0;
}

运行以后可以看到,当我们实例化的对象为指针类型或者引用类型的时候,就会去调用这两个特化模板。 


💧模板特化的应用示例 

 我们还是拿日期类来举例,假设我现在要对3个实例化对象进行排序


// Less模板 --- 比较小于
template<class T>
struct Less
{bool operator()(const T& x, const T& y) const{return x < y;}
};int main()
{Date d1(2024, 7, 7);Date d2(2024, 7, 6);Date d3(2024, 7, 8);vector<Date> v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 排序sort(v1.begin(), v1.end(), Less<Date>());// 打印for (auto e : v1){cout << e;}return 0;
}
  •  可以看到,此时是能直接排序的,结果是日期升序。

 那 如果我将 vector 里面存放的是 Date* 类型的数据,还能排序吗?

// Less模板 --- 比较小于
template<class T>
struct Less
{bool operator()(const T& x, const T& y) const{return x < y;}
};int main()
{Date d1(2024, 7, 7);Date d2(2024, 7, 6);Date d3(2024, 7, 8);vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 排序sort(v2.begin(), v2.end(), Less<Date*>());// 打印for (auto e : v2) {cout << *e << endl;}return 0;
}

 因为,v2 当中存放的地址,所以我们打印的时候要解引用,打印以后看到,日期还不是升序呀,那么我们排序的到底是什么呢?

如果我们不解引用,直接打印v2的每个元素可以看到,v2 中放的地址是升序的。因为此处需要在排序过程中,让sort 比较v2中存放地址指向的日期对象,但是走了Less模板,sort 在排序时实际比较的是v2中指针的地址,因此无法达到预期。

通过观察上述程序的结果发现,对于日期对象可以直接排序,并且结果是正确的。但是如果待排序元素是指针,结果就不一定正确。 

因为: sort 最终按照Less模板中的方式比较,所以只会比较指针,而不是比较指针指向空间中内容。

那么此时可以使用类版本特化来处理上述问题: 

全特化处理: 

// Less模板 --- 比较小于
template<class T>
struct Less
{bool operator()(const T& x, const T& y) const{return x < y;}
};// 对Less类模板按照指针方式特化
template<>
struct Less<Date*>
{bool operator()(Date* x, Date* y) const{return *x < *y;}
};int main()
{Date d1(2024, 7, 7);Date d2(2024, 7, 6);Date d3(2024, 7, 8);vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 排序sort(v2.begin(), v2.end(), Less<Date*>());// 打印for (auto e : v2) {cout << *e;}return 0;
}

 特化之后,再运行就可以得到正确的排序结果了

偏特化处理: 

// Less模板 --- 比较小于
template<class T>
struct Less
{bool operator()(const T& x, const T& y) const{return x < y;}
};//偏特化后的比较模板
template<class T>
class Less<T*>
{
public:bool operator()(T* x, T* y) const{return *x < *y;}
};int main()
{Date d1(2024, 7, 7);Date d2(2024, 7, 6);Date d3(2024, 7, 8);vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 排序sort(v2.begin(), v2.end(), Less<Date*>());// 打印for (auto e : v2) {cout << *e;}return 0;
}

  特化之后,再运行就可以得到正确的排序结果了


五、总结 

模板是 STL 的基础支撑,假若没有模板、没有泛型编程思想,那么恐怕 "STL" 会变得非常大 

模板的优点 

  • 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  • 增强了代码的灵活性

模板的缺点 

  • 模板会导致代码膨胀问题,也会导致编译时间变长
  • 出现模板编译错误时,错误信息非常凌乱,不易定位错误

总之,模板 是一把双刃剑,既有优点,也有缺点,只有把它用好了,才能使代码 更灵活、更优雅 


六、共勉 

以下就是我对 【模板进阶】 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对 C++ 的理解,请持续关注我哦!!!    

相关文章:

【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)

目录 一、前言 二、什么是C模板&#xff1f; &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、非类型模板参数 ⚡问题引入⚡ ⚡非类型模板参数的使用⚡ &#x1f525;非类型模板参数的定义 &#x1f525;非类型模板参数的两种类型 &#x1f52…...

Cookie与Session

Cookie Set-Cookie: sessionIdabc123; ExpiresWed, 09 Jun 2024 10:18:14 GMT; Path/; Secure; HttpOnlySession session作用域 首先需要了解servlet容器可能包含多个web应用。 在servlet容器中同一应用的servlet 对 session数据是可见的&#xff0c;不同应用之间session是相互…...

Nuxt3 的生命周期和钩子函数(十一)

title: Nuxt3 的生命周期和钩子函数&#xff08;十一&#xff09; date: 2024/7/5 updated: 2024/7/5 author: cmdragon excerpt: 摘要&#xff1a;本文详细介绍了Nuxt3中几个关键的生命周期钩子和它们的使用方法&#xff0c;包括webpack:done用于Webpack编译完成后执行操作…...

Windows ipconfig命令详解,Windows查看IP地址信息

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 ipconfig 1、基…...

在C#/Net中使用Mqtt

net中MQTT的应用场景 c#常用来开发上位机程序&#xff0c;或者其他一些跟设备打交道比较多的系统&#xff0c;所以会经常作为拥有数据的终端&#xff0c;可以用来采集上传数据&#xff0c;而MQTT也是物联网常用的协议&#xff0c;所以下面介绍在C#开发中使用MQTT。 安装MQTTn…...

VBA提取word表格内容到excel

这是一段提取word表格中部分内容的vb代码。 Sub 提取word表格() mypath ThisWorkbook.Path & "\"myname Dir(mypath & "*.doc*")n 4 index of rowsRange("A1:F1") Array("课程代码", "课程名称", "专业&…...

html+css+js图片手动轮播

源代码在界面图片后面 轮播演示用的几张图片是Bing上的&#xff0c;直接用的几张图片的URL&#xff0c;谁加载可能需要等一下&#xff0c;现实中替换成自己的图片即可 关注一下点个赞吧&#x1f604; 谢谢大佬 界面图片 源代码 <!DOCTYPE html> <html lang&quo…...

【十三】图解 Spring 核心数据结构:BeanDefinition 其二

图解 Spring 核心数据结构&#xff1a;BeanDefinition 其二 概述 前面写过一篇相关文章作为开篇介绍了一下BeanDefinition&#xff0c;本篇将深入细节来向读者展示BeanDefinition的设计&#xff0c;让我们一起来揭开日常开发中使用的bean的神秘面纱&#xff0c;深入细节透彻理解…...

数据库作业

命令 登陆数据库 mysql -uroot -p123456 --prompt"\u\h:\d--> " 创建数据库zcr create database zcr&#xff1b; 修改数据库zcr字符集为gbk alter database zcr default character set gbk collate gbk_chinese_ci; 选择数据库zcr use zcr 查看数据库zc…...

12、matlab中for循环,if else判断语句,break和continue用法以及switch case语句使用

1、前言 在MATLAB中&#xff0c;for循环用于迭代一个固定次数的循环。可以使用if else语句在循环中进行条件判断&#xff0c;根据条件的不同执行相应的代码块。break和continue可以用于控制循环的执行流程&#xff0c;break用于提前结束循环&#xff0c;而continue用于跳过当前…...

AcWing 3207:门禁系统 ← 桶排序中“桶”的思想

【题目来源】https://www.acwing.com/problem/content/3210/【题目描述】 涛涛最近要负责图书馆的管理工作&#xff0c;需要记录下每天读者的到访情况。 每位读者有一个唯一编号&#xff0c;每条记录用读者的编号来表示。 给出读者的来访记录&#xff0c;请问每一条记录中的读者…...

开发个人Go-ChatGPT--3 服务拆分

开发个人Go-ChatGPT–3 服务拆分 个人Go-ChatGPT项目可拆分用户服务&#xff08;user&#xff09;&#xff0c;AI模型服务&#xff08;AiModel&#xff09;&#xff0c;… 每个服务都可以再分为 api 服务和 rpc 服务。api 服务对外&#xff0c;可提供给 app 调用。rpc 服务是…...

Android --- 新电脑安装Android Studio 使用 Android 内置模拟器电脑直接卡死,鼠标和键盘都操作不了

新电脑安装Android Studio 使用 Android 内置模拟器电脑直接卡死&#xff0c;鼠标和键盘都操作不了 大概原因就是,初始化默认Google的安卓模拟器占用的RAM内存是2048&#xff0c;如果电脑的性能和内存一般的话就可能卡死&#xff0c;解决方案是手动修改安卓模拟器的config文件&…...

从入门到深入,Docker新手学习教程

编译整理&#xff5c;TesterHome社区 作者&#xff5c;Ishaan Gupta 以下为作者观点&#xff1a; Docker 彻底改变了我们开发、交付和运行应用程序的方式。它使开发人员能够将应用程序打包到容器中 - 标准化的可执行组件&#xff0c;将应用程序源代码与在任何环境中运行该代码…...

Postman编写测试脚本

在 Postman 中&#xff0c;编写测试脚本通常使用 JavaScript&#xff0c;这些脚本可以在请求发送前后执行。以下是一些示例代码&#xff0c;展示了如何在 Postman 中使用测试脚本。 1. 测试脚本示例&#xff1a;检查响应状态码 // 测试脚本在请求发送后执行 pm.test("Re…...

代码随想录算法训练Day57|LeetCode200-岛屿数量、LeetCode695-岛屿的最大面积

岛屿数量 题目描述 力扣200-岛屿数量 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此…...

StopWatch的使用

org.springframework.util.StopWatch 是 Spring 框架提供的一个轻量级的计时工具&#xff0c;用于测量代码执行时间。它比 Apache Commons Lang 的 StopWatch 提供了更多的功能&#xff0c;例如累计多个时间段、打印详细报告等。 以下是如何使用 Spring 的 StopWatch&#xff…...

MySQL基础篇(三)数据库的修改 删除 备份恢复 查看连接情况

对数据库的修改主要指的是修改数据库的字符集&#xff0c;校验规则。 将test1数据库字符集改为gbk。 数据库的删除&#xff1a; 执行完该数据库就不存在了&#xff0c;对应数据库文件夹被删除&#xff0c;级联删除&#xff0c;里面的数据表全部被删除。 注意&#xff1a;不要随…...

android手机电视相框项目-学员做出个bug版本邀请大家review提意见

背景 前几天给我的vip学员布置了一个android手机/电视相框的项目&#xff0c;具体详情看如下链接&#xff1a; https://mp.weixin.qq.com/s/l2roDoco-o59SLlORENZlA 这个项目我说过不给提供答案哈&#xff0c;让各位学员朋友自己独立思考完成哈&#xff0c;因为尽量想让大家慢…...

web零碎知识2

不知道我的这个axios的包导进去没。 找一下关键词&#xff1a; http请求协议&#xff1a;就是进行交互式的格式 需要定义好 这个式一发一收短连接 而且没有记忆 这个分为三个部分 第一个式请求行&#xff0c;第二个就是请求头 第三个就是请求体 以get方式进行请求的失手请求…...

Android项目框架

Android项目基于Android Studio开发&#xff0c;Android Studio使用Gradle作为项目构建工具。新建工程后可以看到如图所示目录结构&#xff0c;将Android切成Project可以看到完整的Android工程目录结构&#xff0c;如图所示。 图1-2 Android项目目录结构 app目录是一个典型的…...

vue 模糊查询加个禁止属性

vue 模糊查询加个禁止属性 父组件通过属性传&#xff0c;是否禁止输入-------默认可以输入...

MySQL 主从复制中 MHA 工具的研究与实践

MySQL 主从复制中 MHA 工具的研究与实践 一、MHA 工具简介二、MHA 的工作原理三、MHA 配置步骤环境准备1. 在主服务器上配置主从复制2. 在从服务器上配置复制 安装 MHA 工具1. 安装必要的依赖包2. 下载并安装 MHA 配置 MHA1. 创建 MHA 配置文件2. 配置 SSH 免密登录 测试 MHA1.…...

Hi3861 OpenHarmony嵌入式应用入门--TCP Server

本篇使用的是lwip编写tcp服务端。需要提前准备好一个PARAM_HOTSPOT_SSID宏定义的热点&#xff0c;并且密码为PARAM_HOTSPOT_PSK LwIP简介 LwIP是什么&#xff1f; A Lightweight TCP/IP stack 一个轻量级的TCP/IP协议栈 详细介绍请参考LwIP项目官网&#xff1a;lwIP - A Li…...

Poker Game, Run Fast

Poker Game, Run Fast 扑克&#xff1a;跑得快 分门别类&#xff1a; 单张从小到大默认 A < 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K 跑得快&#xff1a;单张从小到大 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 &…...

订单折扣金额分摊算法|代金券分摊|收银系统|积分分摊|分摊|精度问题|按比例分配|钱分摊|钱分配

一个金额分摊的算法&#xff0c;将折扣分摊按比例&#xff08;细单实收在总体的占比&#xff09;到各个细单中。 此算法需要达到以下要求&#xff1a; 折扣金额接近细单总额&#xff0c;甚至折扣金额等于细单金额&#xff0c;某些时候甚至超过细单总额&#xff0c;要保证实收不…...

Matlab中collectPlaneWave函数的应用

查看文档如下&#xff1a; 可以看出最多5个参数&#xff0c;分别是阵列对象&#xff0c;信号幅度&#xff0c;入射角度&#xff0c;信号频率&#xff0c;光速。 在下面的代码中&#xff0c;我们先创建一个3阵元的阵列&#xff0c;位置为&#xff1a;&#xff08;-1,0,0&#x…...

Linux系统的基础知识和常用命令

1、什么是Linux&#xff1f; 是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹于1991年10月5日首次发布&#xff0c;它主要受到Minix和Unix思想的启发&#xff0c;是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行…...

三相异步电动机的起动方法

1. 引言 2. 三相笼型异步电动机德起动方法 3. 三相绕线型异步电动机的起动方法 4. 软起动器起动 5. 参考文献 1 引言 三相异步电动机结构简单﹑价格低廉﹑运行可靠﹑维护方便&#xff0c;在工农业生产中得到了广泛应用。为使电动机能够转动起来&#xff0c;并很快达到工作转…...

【LinuxC语言】手撕Http协议之accept_request函数实现(一)

文章目录 前言accept_request函数作用accept_request实现解析方法根据不同方法进行不同操作http服务器响应格式unimplemented函数实现总结前言 在计算机网络中,HTTP协议是一种常见的应用层协议,它定义了客户端和服务器之间如何进行数据交换。在这篇文章中,我们将深入探讨Li…...

Redis Cluster 模式 的具体实施细节是什么样的?

概述 参考&#xff1a;What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium Redis Cluster 的工作原理是将数据分布在多个节点上&#xff0c;同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述&#xff1a; …...

基于大模型的机器人控制

基于大模型的机器人控制是指利用深度学习中的大型神经网络模型来实现对机器人的精确控制。这种方法结合了深度学习的强大表征学习能力和机器人控制的实际需求&#xff0c;旨在提高机器人的自主性、灵活性和智能性。 基本原理 数据收集&#xff1a;首先&#xff0c;需要收集大量…...

在 PostgreSQL 中,如何处理数据的版本控制?

文章目录 一、使用时间戳字段进行版本控制二、使用版本号字段进行版本控制三、使用历史表进行版本控制四、使用 RETURNING 子句获取更新前后的版本五、使用数据库触发器进行版本控制 在 PostgreSQL 中&#xff0c;处理数据的版本控制可以通过多种方式实现&#xff0c;每种方式都…...

Rust 组织管理

Rust 组织管理 Rust 是一种系统编程语言&#xff0c;以其内存安全性、速度和并发性而闻名。它由 Mozilla 开发&#xff0c;并得到了一个庞大而活跃的社区的支持。Rust 的组织管理涉及多个方面&#xff0c;包括项目管理、社区参与、工具和库的维护&#xff0c;以及生态系统的整…...

vb.netcad二开自学笔记1:万里长征第一步Hello CAD!

已入门的朋友请绕行&#xff01; 今天开启自学vb.net 开发autocad&#xff0c;网上相关资料太少了、太老了。花钱买课吧&#xff0c;穷&#xff01;又舍不得&#xff0c;咬牙从小白开始摸索自学吧&#xff0c;虽然注定是踏上了一条艰苦之路&#xff0c;顺便作个自学笔记备忘!积…...

Vue的学习之数据与方法

前段期间&#xff0c;由于入职原因没有学习&#xff0c;现在已经正式入职啦&#xff0c;接下来继续加油学习。 一、数据与方法 文字备注已经在代码中&#xff0c;方便自己学习和理解 <!DOCTYPE html> <html><head><meta charset"utf-8">&l…...

刷题——在二叉树中找到最近公共祖先

在二叉树中找到两个节点的最近公共祖先_牛客题霸_牛客网 int lowestCommonAncestor(TreeNode* root, int o1, int o2) {if(root NULL) return -1;if((root->val o1) || (root->val o2)) return root->val;int left lowestCommonAncestor(root->left, o1, o2);i…...

nginx(三)—从Nginx配置熟悉Nginx功能

一、 Nginx配置文件结构 ... #全局块events { #events块... }http #http块 {... #http全局块server #server块{ ... #server全局块location [PATTERN] #location块{...}location [PATTERN] {...}}server{...}... #http全局块 …...

Python轮子:文件比较器——filecmp

原文链接&#xff1a;http://www.juzicode.com/python-module-filecmp filecmp模块可以用来比较文件或者目录。 安装和导入 filecmp是Python自带的模块&#xff0c;不需要额外安装&#xff0c;直接导入即可&#xff1a; import filecmp as fc #或者 import filecmp cmp()比较…...

uni-app组件 子组件onLoad、onReady事件无效

文章目录 导文解决方法 导文 突然发现在项目中&#xff0c;组件 子组件的onLoad、onReady事件无效 打印也出不来值 怎么处理呢&#xff1f; 解决方法 mounted() {console.log(onLoad, this.dateList);//有效// this.checkinDetails()},onReady() {console.log(onReady, this.da…...

leetcode力扣_排序问题

215.数组中的第K个最大元素 鉴于已经将之前学的排序算法忘得差不多了&#xff0c;只会一个冒泡排序法了&#xff0c;就写了一个冒牌排序法&#xff0c;将给的数组按照降序排列&#xff0c;然后取nums[k-1]就是题目要求的&#xff0c;但是提交之后对于有的示例显示”超出时间限制…...

在 .NET 8 Web API 中实现弹性

在现代 Web 开发中&#xff0c;构建弹性 API 对于确保可靠性和性能至关重要。本文将指导您使用 Microsoft.Extensions.Http.Resilience 库在 .NET 8 Web API 中实现弹性。我们将介绍如何设置重试策略和超时&#xff0c;以使您的 API 更能抵御瞬时故障。 步骤 1.创建一个新的 .…...

linux下高级IO模型

高级IO 1.高级IO模型基本概念1.1 阻塞IO1.2 非阻塞IO1.3 信号驱动IO1.4 IO多路转接1.5 异步IO 2. 模型代码实现2.1 非阻塞IO2.2 多路转接-selectselect函数介绍什么才叫就绪呢&#xff1f;demoselect特点 2.3 多路转接-pollpoll函数介绍poll优缺点demo 2.4 多路转接-epoll&…...

掌握Mojolicious会话管理:构建安全、持久的Web应用

掌握Mojolicious会话管理&#xff1a;构建安全、持久的Web应用 Mojolicious是一个基于Perl的高性能、异步Web开发框架&#xff0c;它提供了一套完整的工具来构建现代Web应用。会话管理是Web开发中的一个关键组成部分&#xff0c;它允许应用识别和保持用户的登录状态。本文将深…...

24西安电子科技大学马克思主义学院—考研录取情况

01、马克思主义学院各个方向 02、24马克思主义学院近三年复试分数线对比 PS&#xff1a;马院24年院线相对于23年院线增加15分&#xff0c;反映了大家对于马克思主义理论学习与研究的热情高涨&#xff0c;也彰显了学院在人才培养、学科建设及学术研究等方面的不断进步与成就。 6…...

12--RabbitMQ消息队列

前言&#xff1a;前面一章内容太多&#xff0c;写了kafka&#xff0c;这里就写一下同类产品rabbitmq&#xff0c;rabbitmq内容较少&#xff0c;正好用来过度一下&#xff0c;概念还是会用一些例子来说明&#xff0c;实际部署的内容会放在概念之后。 1、基础概念 1.1、MQ消息队…...

VMware替换关键技术:核心业务系统中,访存密集型应用的性能优化

越来越多用户采用虚拟化、超融合以及云平台环境来承载其核心业务&#xff0c;核心业务的高并发对性能的要求尤为严格&#xff0c;在VMware替换的热潮下&#xff0c;原VMware用户也更为关注新平台在核心业务上的性能表现是否对标&#xff0c;或实现超越。深信服将通过系列解析&a…...

[单master节点k8s部署]20.监控系统构建(五)Alertmanager

prometheus将监控到的异常事件发送给Alertmanager&#xff0c;然后Alertmanager将报警信息发送到邮箱等设备。可以从下图看出&#xff0c;push alerts是由Prometheus发起的。 安装Alertmanager config文件 [rootmaster prometheus]# cat alertmanager-cm.yaml kind: ConfigMa…...

用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由

1.下载依赖&#xff1a; npm install vue-router 在src目录下新建一个文件夹router&#xff0c;在router文件夹下新建一个文件router.js文件,在component目录下新建增加删除和修改的组件&#xff0c;引入router.js当中 此时的init组件为主页面&#xff08;&#xff08;二、三&…...

磁盘就是一个超大的Byte数组,操作系统是如何管理的?

磁盘在操作系统的维度看&#xff0c;就是一个“超大的Byte数组”。 那么操作系统是如何对这块“超大的Byte数组”做管理的呢&#xff1f; 我们知道在逻辑上&#xff0c;上帝说是用“文件”的概念来进行管理的。于是&#xff0c;便有了“文件系统”。那么&#xff0c;文件系统…...