【C++】set、map 容器的使用

news2025/5/23 6:04:16

文章目录

  • 1. set 和 multiset 的使用
    • 1.1 set类的介绍
    • 1.2 set的构造和迭代器
    • 1.3 set 的增删查
    • 1.4 insert和迭代器调用示例
    • 1.5 find和erase使用示例
    • 1.6 multiset和set的差异
  • 2. map 和 multimap 的使用
    • 2.1 map 类的介绍
    • 2.2 pair 类型介绍
    • 2.3 map 的构造和迭代器
    • 2.4 map 的增删查
    • 2.5 map 的数据修改
    • 2.6 构造遍历及增删查使用示例
    • 2.7 map 的迭代器和 [] 功能示例
    • 2.8 multimap和map的差异

1. set 和 multiset 的使用

1.1 set类的介绍

  • set的声明如下,T就是set底层关键字的类型
  • set默认要求T支持小于比较,如果不支持或者想按自己的需求走可以自行实现仿函数传给第二个模版参数
  • set底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参数。
  • 一般情况下,我们都不需要传后两个模版参数。
  • set底层是用红黑树实现,增删查效率是O(logN),迭代器遍历是走的搜索树的中序,所以是有序的。
  • 前面部分我们已经学习了vector/list等容器的使用,STL容器接口设计,高度相似,所以这里我们就不再一个接口一个接口的介绍。
template < class T, // set::key_type/value_type
	class Compare = less<T>, // set::key_compare/value_compare
	class Alloc = allocator<T> // set::allocator_type
	> class set;

1.2 set的构造和迭代器

set的构造我们关注以下几个接口即可。

set的支持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是二叉搜索树,迭代器遍历走的中序;支持迭代器就意味着支持范围for,set的iterator和const_iterator都不支持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构。

// empty (1) 无参默认构造
explicit set(const key_compare& comp = key_compare(),
	const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
set(InputIterator first, InputIterator last,
	const key_compare& comp = key_compare(),
	const allocator_type & = allocator_type());
// copy (3) 拷贝构造
set(const set& x);
// initializer list (5) initializer 列表构造
set(initializer_list<value_type> il,
	const key_compare& comp = key_compare(),
	const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator->a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

1.3 set 的增删查

常用的几个接口:

// 单个数据插入,如果已经存在则插入失败
pair<iterator, bool> insert(const value_type& val);
// 列表插入,已经在容器中存在的值不会插入
void insert(initializer_list<value_type> il);
// 迭代器区间插入,已经在容器中存在的值不会插入
template <class InputIterator>
void insert(InputIterator first, InputIterator last);
// 查找val,返回val所在的迭代器,没有找到返回end()
iterator find(const value_type& val);
// 查找val,返回Val的个数
size_type count(const value_type& val) const;
// 删除一个迭代器位置的值
iterator erase(const_iterator position);
// 删除val,val不存在返回0,存在返回1
size_type erase(const value_type& val);
// 删除一段迭代器区间的值
iterator erase(const_iterator first, const_iterator last);
// 返回大于等val位置的迭代器
iterator lower_bound(const value_type& val) const;
// 返回大于val位置的迭代器
iterator upper_bound(const value_type& val) const;

1.4 insert和迭代器调用示例

void test1()
{
	// 去重+升序排序
	set<int> s;
	// 去重+降序排序(给一个大于的仿函数)
	//set<int, greater<int>> s;
	s.insert(5);
	s.insert(2);
	s.insert(7);
	s.insert(5);
	//set<int>::iterator it = s.begin();
	auto it = s.begin();
	while (it != s.end())
	{
		// error C3892: “it”: 不能给常量赋值
		// *it = 1;
		cout << *it << " ";
		++it;
	} 
	cout << endl;
	// 插入一段initializer_list列表值,已经存在的值插入失败
	s.insert({ 2,8,3,9 });
	for (auto e : s)
	{
		cout << e << " ";
	} 
	cout << endl;
	set<string> strset = { "sort", "insert", "add" };
	// 遍历string比较ascll码大小顺序遍历的
	for (auto& e : strset)
	{
		cout << e << " ";
	} 
	cout << endl;
}

在这里插入图片描述

1.5 find和erase使用示例

void test2()
{
	set<int> s = { 4,2,7,2,8,5,9 };
	for (auto e : s)
	{
		cout << e << " ";
	} 
	cout << endl;
	// 删除最小值
	s.erase(s.begin());
	for (auto e : s)
	{
		cout << e << " ";
	}

	cout << endl;
	// 直接删除x
	int x;
	cin >> x;
	int num = s.erase(x);
	if (num == 0)
	{
		cout << x << "不存在!" << endl;
	} 
	for (auto e : s)
	{
		cout << e << " ";
	} 
	cout << endl;
	// 直接查找在利用迭代器删除x
	cin >> x;
	auto pos = s.find(x);
	if (pos != s.end())
	{
		s.erase(pos);
	} 
	else
	{
		cout << x << "不存在!" << endl;
	} 
	for (auto e : s)
	{
		cout << e << " ";
	} 
	cout << endl;
	// 算法库的查找 O(N)
	auto pos1 = find(s.begin(), s.end(), x);
	// set自身实现的查找 O(logN)
	auto pos2 = s.find(x);
	// 利用count间接实现快速查找
	cin >> x;
	if (s.count(x))
	{
		cout << x << "在!" << endl;
	}
	else
	{
		cout << x << "不存在!" << endl;
	}
}

在这里插入图片描述

1.6 multiset和set的差异

multiset和set的使用基本完全类似,主要区别点在于 multiset 的 允许重复,可存储多个相同值的元素,而 set 的 唯一,不允许重复元素
,具体参看下面的样例代码理解。

#include <iostream>
#include <set>

int main() 
{
    std::set<int> s = {1, 2, 2, 3};      // 实际存储 {1, 2, 3}
    std::multiset<int> ms = {1, 2, 2, 3}; // 存储 {1, 2, 2, 3}

    std::cout << "set size: " << s.size() << "\n";      // 输出 3
    std::cout << "multiset size: " << ms.size() << "\n";// 输出 4
}

同样的,在删除时,multiset 也会删除所有匹配 key 的元素,而 set 只会删除一个匹配元素。

std::multiset<int> ms = {2, 2, 3};
ms.erase(2);       // 删除所有2 → 剩余 {3}

std::set<int> s = {2, 3};
s.erase(2);        // 删除2 → 剩余 {3}

在查找时 multiset 返回键的出现次数(可能 >1),而 set 返回 0 或 1。

std::multiset<int> ms = {1, 2, 2, 3};
std::cout << ms.count(2);   // 输出 2

std::set<int> s = {1, 2, 3};
std::cout << s.count(2);    // 输出 1

迭代器遍历时,multiset 的相同值是连续出现的

std::multiset<int> ms = {3, 1, 2, 2};
for (int num : ms) 
{
    std::cout << num << " ";  // 输出: 1 2 2 3
}

std::set<int> s = {3, 1, 2, 2};
for (int num : s) 
{
    std::cout << num << " ";  // 输出: 1 2 3
}

multiset 的特殊方法
multiset 提供额外方法处理重复键:

  • equal_range(key):返回一个迭代器对,表示所有匹配 key 的元素范围。
  • lower_bound(key)/upper_bound(key):配合范围操作。
std::multiset<int> ms = {1, 2, 2, 3};
auto [first, last] = ms.equal_range(2);
for (auto it = first; it != last; ++it) 
{
    std::cout << *it << " ";  // 输出: 2 2
}

总结

特性setmultiset
键唯一性唯一允许重复
插入行为忽略重复接受重复
删除行为删除单个匹配元素删除所有匹配元素
查找结果存在性检查(0或1)统计出现次数(>=0)
典型应用唯一键管理允许重复的有序数据场景

2. map 和 multimap 的使用

2.1 map 类的介绍

map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key支持小于比较,如果不支持或者需要的话可以自行实现仿函数传给第二个模版参数,map底层存储数据的内存是从空间配置器申请的。一般情况下,我们都不需要传后两个模版参数。map底层是用红黑树实现,增删查改效率是O(logN),迭代器遍历是走的中序,所以是按key有序顺序遍历的

template < class Key, // map::key_type
	class T, // map::mapped_type
	class Compare = less<Key>, // map::key_compare
	class Alloc = allocator<pair<const Key, T> > // map::allocator_type
	> class map;

2.2 pair 类型介绍

map底层的红黑树节点中的数据,使⽤pair<Key, T>存储键值对数据。

typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first;
	T2 second;
	pair() : first(T1()), second(T2())
	{
	}
	pair(const T1& a, const T2& b) : first(a), second(b)
	{
	}
	template<class U, class V>
	pair(const pair<U, V>& pr) : first(pr.first), second(pr.second)
	{
	}
};
template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{
	return (pair<T1, T2>(x, y));
}

2.3 map 的构造和迭代器

// empty (1) 无参默认构造
explicit map(const key_compare& comp = key_compare(),
	const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
map(InputIterator first, InputIterator last,
	const key_compare& comp = key_compare(),
	const allocator_type & = allocator_type());
// copy (3) 拷⻉构造
map(const map& x);
// initializer list (5) initializer 列表构造
map(initializer_list<value_type> il,
	const key_compare& comp = key_compare(),
	const allocator_type& alloc = allocator_type());
// 迭代器是一个双向迭代器
iterator->a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

2.4 map 的增删查

常用的几个接口:

// 单个数据插入,如果已经key存在则插入失败,key存在相等value不相等也会插入失败
pair<iterator, bool> insert(const value_type& val);
// 列表插入,已经在容器中存在的值不会插入
void insert(initializer_list<value_type> il);
// 迭代器区间插入,已经在容器中存在的值不会插入
template <class InputIterator>
void insert(InputIterator first, InputIterator last);
// 查找k,返回k所在的迭代器,没有找到返回end()
iterator find(const key_type& k);
// 查找k,返回k的个数
size_type count(const key_type& k) const;
// 删除一个迭代器位置的值
iterator erase(const_iterator position);
// 删除k,k存在返回0,存在返回1
size_type erase(const key_type& k);
// 删除一段迭代器区间的值
iterator erase(const_iterator first, const_iterator last);
// 返回大于等k位置的迭代器
iterator lower_bound(const key_type& k);
// 返回大于k位置的迭代器
const_iterator lower_bound(const key_type& k) const;

2.5 map 的数据修改

前面的 set 不支持修改,是因为它要修改只能修改 key,而它的 key 一旦修改,就可能破坏底层数据结构红黑树。map 可以修改,值的是能够修改它的 value,它的 key 同样也不能修改,若修改会破坏底层数据结构。

map第一个支持修改的方式是通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map 还有一个非常重要的修改接口operator[],但是operator[]不仅仅支持修改,还支持插入数据和查找数据,所以他是一个多功能复合接口
需要注意从内部实现角度,map这里把我们传统说的value值,给的是T类型,typedef为 mapped_type。而 value_type是红黑树结点中存储的pair键值对值。日常使用我们还是习惯将这里的T映射值叫做value。

Member types
key_type->The first template parameter(Key)
mapped_type->The second template parameter(T)
value_type->pair<const key_type, mapped_type>
// 查找k,返回k所在的迭代器,没有找到返回end(),如果找到了通过iterator可以修改key对应的mapped_type值
iterator find(const key_type& k);

// insert插入⼀个pair<key, T>对象
// 1、如果key已经在map中,插入失败,则返回⼀个pair<iterator,bool>对象,返回pair对象
// first是key所在结点的迭代器,second是false
// 2、如果key不在在map中,插入成功,则返回⼀个pair<iterator,bool>对象,返回pair对象
// first是新插入key所在结点的迭代器,second是true
// 也就是说入论插入成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭代器
// 那么也就意味着insert插入失败时充当了查找的功能,正是因为这一点,insert可以用来实现
operator[]
// 需要注意的是这里有两个pair,不要混淆了,⼀个是map底层红黑树节点中存的pair<key, T>,另
⼀个是insert返回值pair<iterator, bool>
pair<iterator, bool> insert(const value_type& val);
mapped_type& operator[] (const key_type& k);
// operator的内部实现
mapped_type& operator[] (const key_type& k)
{
	// 1、如果k不在map中,insert会插入k和mapped_type默认值,同时[]返回结点中存储
	// mapped_type值的引用,那么我们可以通过引用修改返映射值。所以[]具备了插入 + 修改功能
	// 2、如果k在map中,insert会插入失败,但是insert返回pair对象的first是指向key结点的
	// 迭代器,返回值同时[]返回结点中存储mapped_type值的引用,所以[]具备了查找 + 修改的功能
	pair<iterator, bool> ret = insert({ k, mapped_type() });
	iterator it = ret.first;
	return it->second;
}

2.6 构造遍历及增删查使用示例

void test3()
{
	// initializer_list构造及迭代遍历
	map<string, string> dict = { {"left", "左边"}, {"right", "右边"},
	{"insert", "插入"},{ "string", "字符串" } };
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//cout << (*it).first <<":"<<(*it).second << endl;
		// map的迭代基本都使用operator->,这里省略了一个->
		// 第一个->是迭代器运算符重载,返回pair*,第二个箭头是结构指针解引用取pair数据
			//cout << it.operator->()->first << ":" << it.operator->()-> second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	// insert插入pair对象的4种方式,对⽐之下,最后⼀种最方便
	pair<string, string> kv1("first", "第一个");
	dict.insert(kv1);
	dict.insert(pair<string, string>("second", "第二个"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert({ "auto", "自动的" });
	// "left"已经存在,插入失败
	dict.insert({ "left", "左边,剩余" });
	// 范围for遍历
	for (const auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
	string str;
	while (cin >> str)
	{
		auto ret = dict.find(str);
		if (ret != dict.end())
		{
			cout << "->" << ret->second << endl;
		}
		else
		{
			cout << "无此单词,请重新输入" << endl;
		}
	}
}

在这里插入图片描述

2.7 map 的迭代器和 [] 功能示例

void test4()
{
	// 利用find和iterator修改功能,统计水果出现的次数
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
	"苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (const auto& str : arr)
	{
		// 先查找水果在不在map中
		// 1、不在,说明水果第一次出现,则插入{水果, 1}
		// 2、在,则查找到的节点中水果对应的次数++
		auto ret = countMap.find(str);
		if (ret == countMap.end())
		{
			countMap.insert({ str, 1 });
		}
		else
		{
			ret->second++;
		}
	}
	for (const auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}

在这里插入图片描述

void test5()
{
	// 利用[]插入+修改功能,巧妙实现统计水果出现的次数
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
	"苹果", "香蕉", "苹果", "香蕉" };
	map<string, int> countMap;
	for (const auto& str : arr)
	{
		// []先查找水果在不在map中
		// 1、不在,说明⽔果第⼀次出现,则插入{⽔果, 0},同时返回次数的引用,++一下就变成1次了
		// 2、在,则返回水果对应的次数++
			countMap[str]++;
	} 
	for (const auto & e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	} 
	cout << endl;
}

在这里插入图片描述

void test6()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	// key不存在->插入 {"insert", string()}
	dict["insert"];
	// 插入+修改
	dict["left"] = "左边";
	// 修改
	dict["left"] = "左边、剩余";
	// key存在->查找
	cout << dict["left"] << endl;
}

在这里插入图片描述

2.8 multimap和map的差异

multimap和map的使用基本完全类似,主要区别点在于multimap支持关键值key冗余,那么insert/find/count/erase都围绕着支持关键值key冗余有所差异,这里跟set和multiset完全一样,比如find时,有多个key,返回中序第一个。其次就是multimap不支持[],因为支持key冗余,[]就只能支持插入了,不能支持修改

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】第1节|全面理解MySQL架构

快速安装MySQL 使用Docker快速安装mysql8 docker run -d \ --name mysql8 \ --privilegedtrue \ --restartalways \ -p 13306:3306 \ -v /home/mysql8/data:/var/lib/mysql \ -v /home/mysql8/config:/etc/mysql/conf.d \ -v /home/mysql8/logs:/logs \ -e MYSQL_ROOT_PAS…

YOLOv8模型剪枝笔记(DepGraph和Network Slimming网络瘦身)

文章目录 一、DepGraph剪枝&#xff08;1&#xff09;项目准备1&#xff09;剪枝基础知识2&#xff09;DepGraph剪枝论文解读12&#xff09;DepGraph剪枝论文解读23&#xff09;YOLO目标检测系列发展史4&#xff09;YOLO网络架构 &#xff08;2&#xff09;项目实战&#xff08…

App Builder技术选型指南:从AI编程到小程序容器,外卖App开发实战

在2025年快速迭代的技术生态中&#xff0c;开发者构建App的路径愈发多样化。本文以开发一个同城外卖App为例&#xff0c;对比当前主流的AI编程工具&#xff08;如Cursor、GitHub Copilot、Trae&#xff09;与小程序容器技术&#xff08;如FinClip&#xff09;的优劣势、难易度及…

TDengine 高可用——三副本

概述 TDengine 的三副本方案采用 RAFT 算法来实现数据的一致性&#xff0c;包括元数据和时序数据。一个虚拟节点组&#xff08;VGroup&#xff09;构成了一个 RAFT 组&#xff1b;VGroup 中的虚拟节点&#xff08;Vnode&#xff09;&#xff0c;便是该 RAFT 组的成员节点&…

el-table高度自适应、数据查询后高度展示错误问题

在很多场景中我们需要实现表格的高度自适应&#xff0c;即不同屏幕大小下需要使用不同的高度来设置表格&#xff0c;那么我们应该如何实现呢&#xff1f; 1.el-table实现高度自适应 通过以下代码可以实现表格根据屏幕进行自适应 设置表格的高度 <el-table ref"tableD…

Java接口设计:ECharts热力图的绘制

引言 热力图是一种强大的数据可视化工具&#xff0c;通过颜色的深浅变化来直观展示数据密度和分布情况。在现代Web应用中&#xff0c;ECharts作为一款流行的开源数据可视化库&#xff0c;提供了丰富的图表类型&#xff0c;其中热力图因其直观的视觉效果而被广泛使用。本教程将…

深入理解 MongoDB 的 _id 和 ObjectId:从原理到实践

在 MongoDB 的世界中&#xff0c;_id 字段和 ObjectId 是每个开发者都必须理解的核心概念。作为 MongoDB 文档的唯一标识符&#xff0c;它们不仅影响着数据库的设计&#xff0c;也直接关系到应用的性能和扩展性。本文将全面剖析 _id 和 ObjectId 的工作原理、实际应用场景以及最…

【notepad++如何设置成中文界面呢?】

“Notepad”是一款非常强大的文本编辑软件&#xff0c;将其界面设置成中文的方法如下&#xff1a; 一、工具&#xff0f;原料&#xff1a; 华为 Matebook 15、Windows 10、Notepad 8.4.6。 二 、具体步骤&#xff1a; 1、找到任意一个文本文件&#xff0c;比如 txt 格式的文…

当AI遇上科研:北大“科学导航”重塑学术探索全流程

在人工智能技术迅猛发展的当下&#xff0c;一场悄然发生的变革&#xff0c;正在改变我们“做科研”的方式。近日&#xff0c;北京大学科学智能研究院联合深势科技&#xff0c;正式上线一款面向科研人员的一体化AI平台——Science Navigator&#xff08;科学导航&#xff09;。这…

PHP学习笔记(八)

目录 返回值 return的使用 多值返回的替代方案 可变函数 内部&#xff08;内置&#xff09;函数 匿名函数 静态匿名函数 返回值 值通过可选参数的返回语句返回 return的使用 函数不能返回多个值&#xff0c;但可以通过返回一个数组来得到类似的效果 函数返回一个引用&am…

C#中WSDL文件引用问题

工作中碰到一个单点登录的需求&#xff0c;因为这个需求同事别的系统已经做过&#xff0c;我这边只需要把代码迁移过来即可&#xff0c;但是迁移过程中发现引用WSDL文件后&#xff0c;方法报错的问题&#xff0c;各种排查代码之后未解决&#xff0c;最终发现是WSDL文件引用的问…

养生新策:五维开启健康生活

一、饮食&#xff1a;天然食材&#xff0c;科学配比 以 “原型食物” 为主&#xff0c;减少加工食品摄入。早餐用鹰嘴豆泥涂抹全麦面包&#xff0c;搭配水煮蛋和一小把蓝莓&#xff0c;兼顾蛋白质与抗氧化物质&#xff1b;午餐选择藜麦饭&#xff0c;配上香煎鸡胸肉和蒜蓉空心…

centos8 配置网桥,并禁止kvm默认网桥

环境背景&#xff1a; 我使用vmware部署了一台kvm服务器&#xff0c;网络模式是nat。我想要kvm创建的虚拟机可以访问公网&#xff1b;所以kvm默认的地址不行&#xff0c;我必须使用nat地址才可以&#xff1b; 实现方式&#xff1a; 创建一个网桥&#xff0c;将本地的网络接口…

【Node.js】全栈开发实践

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. Node.js 全栈开发概述1.1 全栈开发的优势1.2 Node.js 全栈开发技术栈 2. 开发环境搭建2.1 Node.js 和 npm 安装2.2 开发工具安装2.3 版本控制设置2.4 项目初始化流程 3. 后端开发 (Node.js)3.1 Express 框架…

ubuntu sh安装包的安装方式

ubuntu sh安装包的安装方式以Miniconda2为例 https://repo.anaconda.com/miniconda/ 如果需要python2.7版本可下载以下版本 Miniconda2-latest-Linux-x86_64.sh 打开终端输入安装命令 sudo sh Miniconda2-latest-Linux-x86_64.sh 然后按提示安装&#xff0c;注意安装位置 …

OpenAI宣布:核心API支持MCP,助力智能体开发

今天凌晨&#xff0c;OpenAI全资收购io的消息成为头条。同时&#xff0c;OpenAI还宣布其核心API——Responses API支持MCP服务。过去&#xff0c;开发智能体需通过函数调用与外部服务交互&#xff0c;过程复杂且延迟高。而今&#xff0c;Responses API支持MCP后&#xff0c;开发…

微服务中的 AKF 拆分原则:构建可扩展系统的核心方法论

在数字化浪潮的推动下&#xff0c;互联网应用规模呈指数级增长&#xff0c;传统单体架构逐渐暴露出难以扩展、维护成本高等问题&#xff0c;微服务架构应运而生并成为企业应对复杂业务场景的主流选择。然而&#xff0c;随着业务的不断扩张和用户量的持续增加&#xff0c;如何确…

vue element-plus 集成多语言

main.js中 // 引入i18n import i18n from /i18n/index 使用i18 app.use(i18n) 在App.vue中 <template><el-config-provider :locale"locale" namespace"el" size"small"><router-view /></el-config-provider> </tem…

如何测试JWT的安全性:全面防御JSON Web Token的安全漏洞

在当今的Web应用安全领域&#xff0c;JSON Web Token(JWT)已成为身份认证的主流方案&#xff0c;但OWASP统计显示&#xff0c;错误配置的JWT导致的安全事件占比高达42%。本文将系统性地介绍JWT安全测试的方法论&#xff0c;通过真实案例剖析典型漏洞&#xff0c;帮助我们构建全…

车载网关策略 --- 车载网关重置前的请求转发机制

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…