从0开始C++(六):模板与容器的使用详讲

目录

一、模板

函数模板

实例

类模板

实例

二、容器

标准模板类STL

容器的概念

数组(array)

向量 (vector)

列表 (list)

队列 (queue)

双端队列 (deque)

集合 (set)

映射 (map)

哈希集合 (unordered_set)

哈希映射 (unordered_map)

三、迭代器


一、模板

模板是一种泛型编程的工具,它允许在编译时对代码进行参数化。使用模板可以编写通用的代码,可以适用于多种不同类型的数据,使得代码可以更加通用和灵活。通过使用模板,可以减少代码重复,提高代码的可重用性和可维护性。

模板的语法使用尖括号 < > 来定义模板参数,参数可以是类型参数或非类型参数。类型参数可以用来指定函数或类的参数类型,非类型参数可以用来指定常量或枚举值。

使用模板时,需要在每个参数前加上关键字 template ,并用尖括号< >将参数包裹起来。

C++模板由两种类型:函数模板和类模板。

函数模板

函数模板是一种让函数能够根据不同参数类型进行通用操作的方法。通过使用函数模板,可以在不重复编写相似函数的情况下,对不同类型的数据进行相同的操作。

实例
#include <iostream>
using namespace std;

// 模板函数
template<typename T>  // 可以是class也可以是typename
T add(T a,T b)
{
    return a+b;
}

int main()
{
    string str = "hello ";
    string str2 = "world";
    cout << add(12,32) << endl; // 44

    cout << add(str,str2) << endl; //hello world
    return 0;
}

类模板

类模板是一种允许定义通用类的方法。类模板可以定义一个模板类,该类可以根据不同的参数类型生成不同的具体类。这样可以避免为每个具体类型编写单独的类。

实例
#include <iostream>

using namespace std;

// 模板类
template<class T>
class Test
{
private:
    T val;
public:
    Test(T v):val(v){}

    T get_val()const
    {
        return val;
    }

    void set_val(const T &val)
    {
        this->val = val;
    }
};

int main()
{

    Test<int> t1(20);
    cout << t1.get_val() << endl;
    t1.set_val(10);
    cout << t1.get_val() << endl;   // 10

    Test<double> t2(0.2);
    cout << t2.get_val() << endl; // 0.2
    t2.set_val(20.3);
    cout << t2.get_val() << endl;

     return 0;
}

二、容器

标准模板类STL

标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。虽说它主要出现到了C++中,但是在被引入C++之前该技术就已经存在了很长时间。

STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。

容器的概念

容器是用来存储数据的集合,数据元素可以是任何类型(因为是使用模板实现)。C++标准库提供了多种容器类,每个容器类都有其特定的特点和适用场景。

常见的C++容器类包括:

  1. 数组 (array):固定大小的连续存储空间,可以快速访问元素。

  2. 向量 (vector):动态数组,可以根据需要调整大小,支持快速随机访问和在尾部插入/删除元素。

  3. 列表 (list):双向链表,可以在任意位置插入/删除元素,但随机访问效率较低。

  4. 前向列表 (forward_list):单向链表,与list类似,但删除操作效率更高。

  5. 堆栈 (stack):后进先出 (LIFO) 的数据结构,只能在顶部插入/删除元素。

  6. 队列 (queue):先进先出 (FIFO) 的数据结构,只能在尾部插入,在头部删除元素。

  7. 双端队列 (deque):双向队列,可以在两端插入/删除元素,支持随机访问。

  8. 集合 (set):有序的唯一元素集合,可以快速插入/删除元素,并支持快速查找。

  9. 映射 (map):键-值对的集合,按照键的顺序进行排序,可以快速插入/删除元素,并支持以键进行查找。

  10. 哈希集合 (unordered_set):无序的唯一元素集合,使用哈希函数实现,插入/删除/查找操作的平均时间复杂度为常数。

  11. 哈希映射 (unordered_map):无序的键-值对集合,使用哈希函数实现,插入/删除/查找操作的平均时间复杂度为常数。

这些容器类提供了丰富的接口和功能,可以根据不同的需求选择合适的容器。另外,C++标准库还提供了算法库,可以方便地对容器中的元素进行各种操作和处理。

数组(array)

array是一种固定大小的连续内存空间,用于存储相同类型的对象。可以使用array类模板来创建数组,以下是array数组的常用操作方法:

1、创建array数组:

#include <array>
std::array<int, 5> myArray; // 创建一个具有5个整数元素的数组

2、获取数组大小:

std::array<int, 5> myArray;
int size = myArray.size(); // 获取数组的大小,返回值为5

3、访问数组元素:

std::array<int, 5> myArray;
myArray[0] = 10; // 使用下标操作符访问和修改数组元素
int value = myArray[1]; // 获取数组的第2个元素的值

4、数组赋值和初始化:

std::array<int, 5> myArray;
myArray = {1, 2, 3, 4, 5}; // 使用花括号列表进行赋值
std::array<int, 5> myArray2 = {6, 7, 8, 9, 10}; // 使用花括号列表进行初始化

5、数组迭代器操作:

std::array<int, 5> myArray = {1, 2, 3, 4, 5};
for (auto it = myArray.begin(); it != myArray.end(); ++it) {
    // 使用迭代器遍历数组元素
    std::cout << *it << " ";
}

6、判断数组是否为空:

std::array<int, 5> myArray;
bool isEmpty = myArray.empty(); // 如果数组为空,则返回true,否则返回false

7、获取数组首尾元素的引用:

std::array<int, 5> myArray = {1, 2, 3, 4, 5};
int& frontElement = myArray.front(); // 获取数组第一个元素的引用
int& backElement = myArray.back(); // 获取数组最后一个元素的引用

8、交换数组内容:

std::array<int, 5> myArray = {1, 2, 3, 4, 5};
std::array<int, 5> myArray2 = {6, 7, 8, 9, 10};
myArray.swap(myArray2); // 交换两个数组的内容

向量 (vector)

vector是一种动态数组,它可以自动调整大小,并且具有很多方便的操作方法。以下是vector向量的常用操作方法:

1、创建vector向量:

#include <vector>
std::vector<int> myVector; // 创建一个整数向量

2、获取向量大小:

std::vector<int> myVector;
int size = myVector.size(); // 获取向量的大小

3、向向量中添加元素:

std::vector<int> myVector;
myVector.push_back(10); // 在向量尾部添加一个元素

4、访问向量元素:

std::vector<int> myVector;
myVector[0] = 10; // 使用下标操作符访问和修改向量元素
int value = myVector[1]; // 获取向量的第2个元素的值

5、向量赋值和初始化:

std::vector<int> myVector;
myVector = {1, 2, 3, 4, 5}; // 使用花括号列表进行赋值
std::vector<int> myVector2 = {6, 7, 8, 9, 10}; // 使用花括号列表进行初始化

6、向量迭代器操作:

std::vector<int> myVector = {1, 2, 3, 4, 5};
for (auto it = myVector.begin(); it != myVector.end(); ++it) {
    // 使用迭代器遍历向量元素
    std::cout << *it << " ";
}

7、判断向量是否为空:

std::vector<int> myVector;
bool isEmpty = myVector.empty(); // 如果向量为空,则返回true,否则返回false

8、获取向量首尾元素的引用:

std::vector<int> myVector = {1, 2, 3, 4, 5};
int& frontElement = myVector.front(); // 获取向量第一个元素的引用
int& backElement = myVector.back(); // 获取向量最后一个元素的引用

9、删除向量中的元素:

std::vector<int> myVector = {1,

列表 (list)

list是一种双向链表,它可以动态地插入和删除元素,并且具有很多方便的操作方法。以下是list列表的一些常用操作方法:

1、创建list列表:

#include <list>
std::list<int> myList; // 创建一个整数列表

2、获取列表大小:

std::list<int> myList;
int size = myList.size(); // 获取列表的大小

3、向列表中添加元素:

std::list<int> myList;
myList.push_back(10); // 在列表尾部添加一个元素
myList.push_front(20); // 在列表头部添加一个元素

4、访问列表元素:

std::list<int> myList;
myList.front() = 10; // 获取和修改列表的第一个元素
int value = myList.back(); // 获取列表的最后一个元素的值

5、列表赋值和初始化:

std::list<int> myList;
myList = {1, 2, 3, 4, 5}; // 使用花括号列表进行赋值
std::list<int> myList2 = {6, 7, 8, 9, 10}; // 使用花括号列表进行初始化

6、列表迭代器操作:

std::list<int> myList = {1, 2, 3, 4, 5};
for (auto it = myList.begin(); it != myList.end(); ++it) {
    // 使用迭代器遍历列表元素
    std::cout << *it << " ";
}

7、判断列表是否为空:

std::list<int> myList;
bool isEmpty = myList.empty(); // 如果列表为空,则返回true,否则返回false

8、删除列表中的元素:

std::list<int> myList = {1, 2, 3, 4, 5};
myList.pop_back(); // 删除列表尾部的元素
myList.pop_front(); // 删除列表头部的元素

9、插入元素到指定位置:

std::list<int> myList = {1, 2, 3, 4, 5};
auto it = std::find(myList.begin(), myList.end(), 3); // 找到值为3的元素的迭代器
myList.insert(it, 10); // 在指定位置插入一个元素

10、移除指定值的元素:

std::list<int> myList = {1, 2, 3, 4, 5};
myList.remove(3); // 移除所有值为3的元素

队列 (queue)

queue是一种队列容器,它遵循先进先出(First-In-First-Out,FIFO)的原则。以下是queue队列的一些常用操作方法:

1、创建queue队列:

#include <queue>
std::queue<int> myQueue; // 创建一个整数队列

2、获取队列大小:

std::queue<int> myQueue;
int size = myQueue.size(); // 获取队列的大小

3、向队列尾部添加元素:

std::queue<int> myQueue;
myQueue.push(10); // 在队列尾部添加一个元素

4、从队列头部移除元素:

std::queue<int> myQueue;
myQueue.pop(); // 移除队列头部的元素

5、获取队列头部元素的值:

std::queue<int> myQueue;
int frontValue = myQueue.front(); // 获取队列头部元素的值

6、获取队列尾部元素的值:

std::queue<int> myQueue;
int backValue = myQueue.back(); // 获取队列尾部元素的值

7、判断队列是否为空:

std::queue<int> myQueue;
bool isEmpty = myQueue.empty(); // 如果队列为空,则返回true,否则返回false

8、清空队列中的元素:

std::queue<int> myQueue;
myQueue = {}; // 清空队列中的所有元素

双端队列 (deque)

在C++中,deque(双端队列)是一种支持在头部和尾部进行插入和删除操作的动态数组。以下是deque的一些常用操作方法:

1、创建deque双端队列:

#include <deque>
std::deque<int> myDeque; // 创建一个整数双端队列

2、获取双端队列大小:

std::deque<int> myDeque;
int size = myDeque.size(); // 获取双端队列的大小

3、向双端队列头部插入元素:

std::deque<int> myDeque;
myDeque.push_front(10); // 在双端队列头部插入一个元素

4、向双端队列尾部插入元素:

std::deque<int> myDeque;
myDeque.push_back(20); // 在双端队列尾部插入一个元素

5、从双端队列头部删除元素:

std::deque<int> myDeque;
myDeque.pop_front(); // 删除双端队列头部的元素

6、从双端队列尾部删除元素:

std::deque<int> myDeque;
myDeque.pop_back(); // 删除双端队列尾部的元素

7、获取双端队列头部元素的值:

std::deque<int> myDeque;
int frontValue = myDeque.front(); // 获取双端队列头部元素的值

8、获取双端队列尾部元素的值:

std::deque<int> myDeque;
int backValue = myDeque.back(); // 获取双端队列尾部元素的值

9、判断双端队列是否为空:

std::deque<int> myDeque;
bool isEmpty = myDeque.empty(); // 如果双端队列为空,则返回true,否则返回false

10、清空双端队列中的元素:

std::deque<int> myDeque;
myDeque.clear(); // 清空双端队列中的所有元素

集合 (set)

set(集合)是一种基于红黑树实现的有序集合容器,它存储唯一的元素,并且按照升序排序。以下是set的一些常用操作方法:

1、创建一个set集合:

#include <set>
std::set<int> mySet; // 创建一个整数集合

2、向集合中插入元素:

std::set<int> mySet;
mySet.insert(10); // 插入一个元素

3、从集合中删除元素:

std::set<int> mySet;
mySet.erase(10); // 删除指定元素

4、检查集合中是否存在元素:

std::set<int> mySet;
bool contains = mySet.count(10); // 如果集合中存在元素10,则返回true,否则返回false

5、获取集合中的元素个数:

std::set<int> mySet;
int size = mySet.size(); // 返回集合中元素的个数

6、遍历集合:

std::set<int> mySet;
for (const auto& element : mySet) {
    // 处理每个元素
}

7、判断集合是否为空:

std::set<int> mySet;
bool isEmpty = mySet.empty(); // 如果集合为空,则返回true,否则返回false

8、清空集合中的元素:

std::set<int> mySet;
mySet.clear(); // 清空集合中的所有元素

映射 (map)

map是一种基于红黑树实现的键值对映射容器,它存储唯一的键和对应的值,并根据键的升序进行排序。以下是map的一些常用操作方法:

1、创建一个map映射:

#include <map>
std::map<int, std::string> myMap; // 创建一个整数到字符串的映射

2、向映射中插入键值对:

std::map<int, std::string> myMap;
myMap.insert(std::make_pair(1, "one")); // 插入一个键值对

3、从映射中删除键值对:

std::map<int, std::string> myMap;
myMap.erase(1); // 删除指定键的键值对

4、访问映射中的值:

std::map<int, std::string> myMap;
std::string value = myMap[1]; // 获取键为1的值

5、检查映射中是否存在键:

std::map<int, std::string> myMap;
bool contains = myMap.count(1); // 如果映射中存在键1,则返回true,否则返回false

6、获取映射中的键值对个数:

std::map<int, std::string> myMap;
int size = myMap.size(); // 返回映射中键值对的个数

7、遍历映射中的键值对:

std::map<int, std::string> myMap;
for (const auto& pair : myMap) {
    int key = pair.first;
    std::string value = pair.second;
    // 处理每个键值对
}

8、判断映射是否为空:

std::map<int, std::string> myMap;
bool isEmpty = myMap.empty(); // 如果映射为空,则返回true,否则返回false

9、清空映射中的键值对:

std::map<int, std::string> myMap;
myMap.clear(); // 清空映射中的所有键值对

哈希集合 (unordered_set)

unordered_set是一种基于哈希表实现的集合容器,它存储唯一的值,并根据哈希值进行快速查找。以下是unordered_set的一些常用操作方法:

1、创建一个unordered_set哈希集合:

#include <unordered_set>
std::unordered_set<int> mySet; // 创建一个整数类型的哈希集合

2、向哈希集合中插入元素:

std::unordered_set<int> mySet;
mySet.insert(1); // 插入一个元素

3、从哈希集合中删除元素:

std::unordered_set<int> mySet;
mySet.erase(1); // 删除指定的元素

4、检查哈希集合中是否存在元素:

std::unordered_set<int> mySet;
bool contains = mySet.count(1); // 如果集合中存在元素1,返回true,否则返回false

5、获取哈希集合的大小:

std::unordered_set<int> mySet;
int size = mySet.size(); // 返回集合中元素的个数

6、遍历哈希集合的元素:

std::unordered_set<int> mySet;
for (const auto& element : mySet) {
    // 处理每个元素
}

7、判断哈希集合是否为空:

std::unordered_set<int> mySet;
bool isEmpty = mySet.empty(); // 如果集合为空,返回true,否则返回false

8、清空哈希集合中的元素:

std::unordered_set<int> mySet;
mySet.clear(); // 清空集合中的所有元素

哈希映射 (unordered_map)

unordered_map是一种基于哈希表实现的映射容器,它存储键值对,并根据键的哈希值进行快速查找。以下是unordered_map的一些常用操作方法:

1、创建一个unordered_map哈希映射:

#include <unordered_map>
std::unordered_map<std::string, int> myMap; // 创建一个键为字符串,值为整数的哈希映射

2、向哈希映射中插入键值对:

std::unordered_map<std::string, int> myMap;
myMap.insert({"apple", 10}); // 插入一个键为"apple",值为10的键值对
myMap["banana"] = 20; // 插入一个键为"banana",值为20的键值对

3、从哈希映射中删除键值对:

std::unordered_map<std::string, int> myMap;
myMap.erase("apple"); // 删除键为"apple"的键值对

4、访问和修改哈希映射中的值:

std::unordered_map<std::string, int> myMap;
int value = myMap["apple"]; // 获取键为"apple"的值
myMap["banana"] = 30; // 修改键为"banana"的值为30

5、检查哈希映射中是否存在键:

std::unordered_map<std::string, int> myMap;
bool contains = myMap.count("apple"); // 如果哈希映射中存在键"apple",返回true,否则返回false

6、获取哈希映射的大小:

std::unordered_map<std::string, int> myMap;
int size = myMap.size(); // 返回哈希映射中键值对的个数

7、遍历哈希映射的键值对:

std::unordered_map<std::string, int> myMap;
for (const auto& pair : myMap) {
    std::string key = pair.first;
    int value = pair.second;
    // 处理每个键值对
}

8、判断哈希映射是否为空:

std::unordered_map<std::string, int> myMap;
bool isEmpty = myMap.empty(); // 如果哈希映射为空,返回true,否则返回false

9、清空哈希映射中的键值对:

std::unordered_map<std::string, int> myMap;
myMap.clear(); // 清空哈希映射中的所有键值对

三、迭代器

迭代器是一种用于遍历和访问容器中元素的对象。迭代器提供了一种通用的访问容器元素的方式,使得我们可以在不依赖具体容器类型的情况下进行遍历和操作。迭代器分为正向迭代器和反向迭代器两种类型,分别用于正向遍历和反向遍历容器。

1、迭代器的定义和获取: 迭代器可以通过容器的成员函数begin()end()来获取。其中,begin()返回指向容器中第一个元素的迭代器,end()返回指向容器尾部的迭代器。

std::vector<int> myVector = {1, 2, 3, 4, 5};
std::vector<int>::iterator it;
for (it = myVector.begin(); it != myVector.end(); ++it) {
    std::cout << *it << " ";
}

2、使用迭代器访问容器元素: 通过解引用操作符*可以获取迭代器指向的元素的值。

std::vector<int> myVector = {1, 2, 3, 4, 5};
std::vector<int>::iterator it = myVector.begin();
std::cout << *it << std::endl; // 输出:1

3、使用迭代器修改容器元素: 通过解引用操作符*可以获取迭代器指向的元素的引用,从而可以修改容器中的元素。

std::vector<int> myVector = {1, 2, 3, 4, 5};
std::vector<int>::iterator it = myVector.begin();
*it = 10; // 修改第一个元素的值

4、迭代器的移动: 迭代器可以通过自增(++)或自减(--)来移动到容器中的下一个或上一个元素。

std::vector<int> myVector = {1, 2, 3, 4, 5};
std::vector<int>::iterator it = myVector.begin();
++it; // 移动到下一个元素
--it; // 移动到上一个元素

5、迭代器的比较: 使用比较操作符(==!=等)可以比较两个迭代器的相对位置。

std::vector<int> myVector = {1, 2, 3, 4, 5};
std::vector<int>::iterator it1 = myVector.begin();
std::vector<int>::iterator it2 = myVector.end();
if (it1 == it2) {
    std::cout << "The iterators are equal." << std::endl;
} else {
    std::cout << "The iterators are not equal." << std::endl;
}

需要注意的是,在使用迭代器时,要确保迭代器指向的元素是存在的,避免越界访问。此外,当容器发生改变(元素的插入、删除等操作)时,迭代器可能会失效,因此在使用迭代器之前要先判断其是否有效。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

热虹吸管的传热计算

热对称管和热管通过使用中空管内的两相流体&#xff0c;在特定的距离上传输大量的热量。 更广泛使用的热管使用吸芯结构将液体输送回热端&#xff0c;而热虹吸管是一个简单的空心管&#xff0c;使用重力。 由于缺乏吸芯结构&#xff0c;使得热虹吸管比传统的热管便宜得多。 然…

自学指南:必备书籍清单--近100本R语言及生物信息相关书籍

R语言是一种功能丰富的编程语言&#xff0c;数据处理、统计分析是大家所熟知的基本功能。开源免费、活跃的全球社区、灵活可扩展等优点促使R语言飞速发展。目前&#xff0c;CRAN 软件包存储库包含 20446 个可用软件包&#xff0c;涵盖了从生物信息到金融分析等广泛的应用领域。…

vue3.0(十五)内置组件Teleport和Suspense

文章目录 一、Teleport1.基本用法2.禁用Teleport3.多个 Teleport 共享目标4.搭配组件 二、 Suspense1.什么是Suspense2.异步依赖3.加载中状态4.事件5.错误处理6.和其他组件结合注意 一、Teleport <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板…

第二十八篇——复盘:世界不完美,我们该怎么办?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 对于信息传递过程中的相关知识的总结&#xff0c;让我又仿佛回到了每一个…

Python列表比较:判断两个列表是否相等的多种方法

&#x1f4d6; 正文 1 通过排序的方式实现判断 list_a [a, b, c, d] list_b [c, d, a, b]if sorted(list_a) sorted(list_b):print(list_a与list_b的元素相等) else:print(list_a与list_b的元素不相等)通过排序&#xff0c;让两组列表中元素一直后进行判断&#xff0c;得到…

Linux常用基本命令

linux目录 1.查看linux本机ip ip addr 2.新建文件夹 mkdir 文件夹名 3.新建文件 touch 文件名.后缀 4.删除文件 rm 文件名.后缀 5.删除文件 rm -r 文件名 6.不询问直接删除 rm -rf 文件名/文件名/ 7.显示目录下文件&#xff0c;文件夹 作用&#xff1a;显示指定目…

人工ai智能写作,分享推荐三款好用软件!

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;而在内容创作领域&#xff0c;AI智能写作软件更是如雨后春笋般涌现。今天&#xff0c;就为大家分享三款备受好评的AI智能写作软件&#xff0c;让你轻松掌握高效写作的秘密…

基于matlab的SVR回归预测

1 原理 SVR&#xff08;Support Vector Regression&#xff09;回归预测原理&#xff0c;基于支持向量机&#xff08;SVM&#xff09;的回归分支&#xff0c;其核心思想是通过寻找一个最优的超平面来进行回归预测&#xff0c;并处理非线性回归问题。以下是SVR回归预测原理的系统…

FFmpeg中位操作相关的源码:GetBitContext结构体,init_get_bits函数、get_bits1函数和get_bits函数分析

一、引言 由《音视频入门基础&#xff1a;H.264专题&#xff08;3&#xff09;——EBSP, RBSP和SODB》可以知道&#xff0c;H.264 码流中的操作单位是位(bit)&#xff0c;而不是字节。因为视频的传输和存贮是十分在乎体积的&#xff0c;对于每一个比特&#xff08;bit&#xf…

策略模式 + 抽象工厂实现多方式登录验证

文章目录 1、需求背景2、常规想法3、工厂模式 配置文件解耦 策略模式4、具体实现5、其他场景6、一点思考 1、需求背景 以gitee为例&#xff0c;登录验证的方式有多种&#xff1a; 用户名密码登录短信验证码登录微信登录 先写一个登录接口&#xff0c;适配所有方式&#xff…

udp协议 服务器

1 TCP和UDP基本概念 TCP:(Transmission Control Protocol)是一种面向连接、可靠的基于字节流的传输层通信协议。并且提供了全双工通信&#xff0c;允许两个应用之间建立可靠的链接以进行数据交换 udp:(User Datagram Protocol):是一种无链接、不可靠、基于数据报文传输层协议&…

websocket服务执行playwright测试

上一篇博客从源码层面分析了playwright vscode插件实现原理&#xff0c;在上一篇博客中提到&#xff0c;backend服务是一个websocket服务。这遍博客将介绍如何封装一个websocket服务&#xff0c;通过发送消息来执行playwright测试。 初始化项目 第一步是初始化项目和安装必要的…

​【VMware】VMware Workstation的安装

目录 &#x1f31e;1. VMware Workstation是什么 &#x1f31e;2. VMware Workstation的安装详情 &#x1f33c;2.1 VMware Workstation的安装 &#x1f33c;2.2 VMware Workstation的无限使用 &#x1f31e;1. VMware Workstation是什么 VMware Workstation是一款由VMwar…

【K8s】专题六:Kubernetes 资源限制及服务质量等级

以下内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01;如果对您有帮助&#xff0c;烦请点赞、关注、转发&#xff01;欢迎扫码关注个人公众号&#xff01; 目录 一、资源限制 1、基本介绍 2、工作原理 3、限制方法 二、服务质量等级 一、资源限制 1…

【软件测试入门】测试用例经典设计方法 — 因果图法

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、因果图设计测试用例的步骤 1、分析需求 阅读需求文档&#xff0c;如果User Case很复杂&am…

DIY灯光特效:霓虹灯动画制作教程

下面我们根据这张霓虹灯案例,教大家如何用智能动物霓虹灯闪烁的效果,大家可以根据思路,实现自己想要的动效效果,一起动手来做吧。 即时设计-可实时协作的专业 UI 设计工具 设置背景 新建画板尺寸为:800PX^600PX,设置背景色#120527。 绘制主题 输入自己喜欢文案,轮廓化,具体…

PHP-CGI的漏洞(CVE-2024-4577)

通过前两篇文章的铺垫&#xff0c;现在我们可以了解 CVE-2024-4577这个漏洞的原理 漏洞原理 CVE-2024-4577是CVE-2012-1823这个老漏洞的绕过&#xff0c;php cgi的老漏洞至今已经12年&#xff0c;具体可以参考我的另一个文档 简单来说&#xff0c;就是使用cgi模式运行的PHP&…

充电桩--充电桩智能化发展趋势

聚焦光伏产业、深耕储能市场、探究充电技术 小Q下午茶 相互交流学习储能和BMS相关内容 43篇原创内容 公众号 一、背景介绍 国家提出“新基建”以来&#xff0c;充电基础设施产业跃入人们的视线成为热门话题。充电基础设施作为充电网、车联网、能源网和物联网的连接器&…

JS对象、数组、字符串超详细方法

JavaScript 对象方法 对象创建的方式 对象字面量 var dog1 {name: "大黄",age: 2,speak: function () {console.log("汪汪");}, };使用Object构造函数 var dog2 new Object(); dog2.name "大黄"; dog2.age 2; dog2.speak function () …

卷积的通俗解释

以时间和空间两个维度分别理解卷积&#xff0c;先用文字来描述&#xff1a; 时间上&#xff0c;任何当前信号状态都是迄至当前所有信号状态的叠加&#xff1b;时间上&#xff0c;任何当前记忆状态都是迄至当前所有记忆状态的叠加&#xff1b;空间上&#xff0c;任何位置状态都…