C++ 的 pair 和 tuple
1 std::pair
1.1 C++ 98 的 std::pair
1.1.1 std::pair 的构造
C++ 的二元组 std::pair<> 在 C++ 98 标准中就存在了,其定义如下:
template<class T1, class T2> struct pair;
std::pair<> 是个类模板,它有两个成员:first 和 second,类型分别是模板参数指定的 T1 和 T2。可以用以下几种方法构造 std::pair<> 类型的变量(对象实例):
std::pair<int, double> ap1; //默认的构造函数
std::pair<int, double> ap2(5,2.8);
std::pair<int, double> ap3(ap2); //拷贝构造函数
ap1 = std::make_pair(6, 7.2); //使用 make_pair函数
std::pair<int, std::string> p4{5, "ak47"}; //C++ 11 初始化列表
std::pair ap5(5, "ak47"); //C++ 17 推断指示语法,将在 1.3 节介绍
1.1.2 赋值与转换
对 std::pair<> 的访问也很简单,直接操作它的两个成员:
std::pair<int, double> ap(5,2.8);
std::cout << ap.first << ", " << ap.second;
ap.first = 42;
如果你的数据中有两个数据耦合比较紧密,经常需要在一起成对出现,而你又不想额外定义一个 struct 的时候,可以考虑使用 std::pair<>。另外,std::pair<> 也可用于函数返回值的类型,这样就可以用一个 return 语句返回两个值。
对于 C++ 来说,std::pair<char, int> 与 std::pair<int, char> 是两个完全不同的类型,它们之间的差别就像 std::string 和 std::vector 的差别一样大。一般来说,两个不同类型的 std::pair<> 变量是不能互相赋值的,但是如果两个 std::pair<> 变量对应的 first 和 second 属性能够对应进行隐式类型转换,则这样的赋值是允许的,比如:
std::pair<char, int> p1('A', 4);
std::pair<int, double> p2 = p1; //OK,隐式转换char -> int, int -> double
除了 C++ 内建的隐式转换,通过自定义构造函数进行的隐式转换也是可以的,比如:
struct FooTest {FooTest(int a){ value = std::format("{}", a); }std::string value;
};std::pair<char, int> p1('A', 4);
std::pair<int, FooTest> p2 = p1; //OK, FooTest(int a) 构造函数完成隐式转换
1.1.3 比较
两个 std::pair<> 变量可以互相比较大小,比较的原则就是先比较 first 属性,如果 first 属性的值相等(按照严格弱序比较)则继续比较 second 属性的值,来看个比较的例子:
std::pair<int, std::string> p1(5, "ak47");
std::pair<int, std::string> p2(5, "ak57");assert(p1 < p2); //5==5,但是 "ak47" < "ak57"
1.2 C++ 11 和 C++ 14 的改进
C++ 11 对 std::pair<> 进行了一些扩展,增加了一个成员函数 swap(),用于和另一个同类型的 std::pair<> 变量交换内容,比如:
std::pair<int, std::string> p1(42, "Hello");
std::pair<int, std::string> p2;
p2.swap(p1);
assert(p2.first == 42);
assert(p1.first == 0);
和其他类型一样,C++ 11 全局的 std::swap() 函数也支持 std::pair<> ,上面的交换代码也可以这样写:
std::swap(p1, p2);
C++ 11 提供的 std::get<> 函数也支持 std::pair<>,可以通过索引(0 或 1)获取一个 std::pair<> 变量的内容,C++ 14 又进行了补充,即可以根据类型匹配获取一个 std::pair<> 变量的内容,比如:
std::pair<int, std::string> p1(42, "Hello");assert(std::get<0>(p1) == std::get<int>(p1));
assert(std::get<1>(p1) == std::get<std::string>(p1));
需要注意,类型匹配的方式只适用于两个不同类型的数据组成的 pair。
此外,一些用于 tuple 类型的操作也可以用于 std::pair<>,比如在编译期获取 std::tuple<> 类型中元素个数的 std::tuple_size,还有在编译期获取 std::tuple<> 类型中每个位置的元素类型的 std::tuple_element<N,T> 等等。对于 std::pair<> 来说,std::tuple_size 得到的值固定是 2,来看个例子:
std::cout << std::tuple_size<std::pair<int, std::string>>::value; //输出 2std::tuple_element<0, std::pair<int, double>>::type a; //变量 a 的类型是 int
这两个方法配合,可以在编译期决断一些事情,比如这个例子:
template<class T>
void Test(const T& t) {int a[std::tuple_size<T>::value] = { 0 }; //定义数组typename std::tuple_element<0, T>::type myValue;myValue = t.first;
}std::pair<int, std::string> p1(5, "ak47");
Test(p1); //此时 myValue 是 int 类型
Test(std::make_pair('A', 4)); //此时 myValue 是 char 类型
1.3 C++ 17 的推断指引
C++ 17 引入了推断指引(Deduction Guides)语法,当然,std::pair<> 也支持推断指引。没有推断指引的时候,构造一个 std::pair <>的对象实例需要指定具体的类型,也就是 std::pair<> 的两个模板参数,就是这样:
std::pair<int, std::string> p1(5, "ak47");
有了推断指引语法之后,代码就可以简化成这个样子:
std::pair p1(5, "ak47");
因为编译器能够从构造 p1 的两个参数中推断出它们的类型,所以就不需要显示指定具体的类型了。推断指引是个好东西,能少敲几次键盘,节省体力。
2 std::tuple
std::tuple 元组是 C++ 11 提供的标准库扩展,利用扩展的参数包语法,std::tuple 实现了对任意个数的非同质元素的聚合。元组是个好东西,有了它可以代替很多琐碎的、毫无价值的传统数据结构(struct)定义。同时,它还支持右值和移动语义,作为参数或返回值传递的时候,比某些构造不良的 struct 具有更好的效率。
2.1 std::tuple 的语法
2.1.1 std::tuple 的构造
std::tuple<> 是个模板类型,其定义如下:
template< class... Types >
class tuple;
class… Types 是参数包语法,Types 就是具体的类型列表。构造 std::tuple<> 对象实例可以借助于构造函数,也可以使用 std::make_tuple() 方法:
std::tuple<int, std::string, double> t1; //默认构造函数
std::tuple<int, std::string, double> t2 = {42, "hello", 2.7};
std::tuple<int, std::string, double> t3{ 42, "hello", 2.7 }; // C++ 11 初始化列表
std::tuple<int, std::string, double> t4(42, "hello", 2.7); //拷贝构造
t1 = t4;
std::tuple<int, std::string, double> t5 = std::make_tuple(42, "hello", 2.7); //右值拷贝构造(move)
auto t5 = std::make_tuple(42, "hello", 2.7); //等价于上一行
std::tuple t6(42, "hello", 2.7); //C++ 17 的推断指示语法,将在 2.2 节介绍
元组中可以使用引用类型,在构造元组的时候指定引用绑定的对象即可,绑定引用对象时可以使用 std::ref,也可以不使用:
int value = 3;
std::tuple<int&, std::string, double> t9(std::ref(value), "hello", 2.7);
//std::tuple<int&, std::string, double> t9(value, "hello", 2.7); 效果一样
std::get<0>(t9) = 4;
std::cout << "value=" << value << ", t9[0]=" << std::get<0>(t9) << std::endl; //4,4
需要注意的是,尽管一些过时的资料中提到 std::tuple<> 采用链式结构存放每个元素的值,但是实际情况并不是这样的。无论 GCC 还是 Visual C++,对元组的存储都是在内存中连续存放的,并且每个同类型的元组使用的内存大小是一样的。以 Visual C++ 为例,元组变量在内存中按照类型列表的倒序方式连续存储在一个内存块中,当然,如果一个对象中使用了指针属性,元组只存储这个对象的内容(包含指针),对象指针属性指向的内容则由对象自己负责存储和释放。
2.1.2 赋值和转换
std::tuple<> 的内部实现是借助于模板的递归推导机制做的,所以无法像 std::pair<> 那样提供成员属性用于访问元组内的各个元素,但是可以借助于同样模板化的 std::get() 方法访问和修改各个元素的值。来看下面的代码:
std::tuple<int, std::string, double> t1(42, "hello", 2.7);
std::cout << std::get<0>(t1); //输出 42
std::get<1>(t1) = "NiHao";
std::cout << std::get<1>(t1); //输出 NiHao
注意,std::get() 中的模板参数 N 不支持动态绑定,即这样写代码是无法编译的:
std::tuple<int, std::string, double> t1(42, "hello", 2.7); for (int i = 0; i < 3; i++)std::cout << i + 1 << ": " << std::get<i>(t1) << std::endl; // 编译错误
当然,可以使用 std::tuple_size 和 std::tuple_element<N,T> 在编译期获得元素的个数和元组各个元素的类型:
// 以下两行代码等价,都输出 3
std::cout << std::tuple_size<std::tuple<int, std::string, double>>::value << std::endl;
std::cout << std::tuple_size<std::tuple<int, std::string, double>>() << std::endl;std::tuple<int, std::string, double> t1(42, "hello", 2.7);
std::cout << std::tuple_size<decltype(t1)>::value << std::endl; //使用 decltypestd::tuple_element<2, std::tuple_size<std::tuple<int, std::string, double>>::type a; //double 类型
std::tuple_element<2, std::tuple_size<decltype(t1)>::type b; //double 类型
std::tuple<> 同样提供了 swap() 方法用于和另一个同类型(或可隐式转换)的 std::tuple<> 对象实例交换内容,当然全局的 std::swap() 方法也支持 std::tuple<>:
std::tuple<int, std::string, double> t1;
std::tuple<int, std::string, double> t2 = {42, "hello", 2.7};t1.swap(t2); //效果与 std::swap(t1, t2); 一样
一般来说,两个不同类型的元组变量是不可以赋值的,但是如果对应位置的元素类型可以隐式转换,那么赋值是可以接受的,比如:
std::tuple<char, double> t16('A', 2.7);
std::tuple<double, std::string> t17 = t16; //错误,无法赋值
std::tuple<int, double> t17 = t16; //OK, char 可以隐式转换成 int
如果元组中的元素类型支持通过构造函数隐式转换,赋值也是可以的,请参考 1.1.2 节 FooTest 的例子,这里不再赘述。
2.1.3 tie 和 ignore
除了使用 std::get() 访问元素的元素,还可以使用 std::tie() 方法将元组内的元素与某个具名的变量关联,将元组的内容传递给具名变量。来看个例子:
std::tuple<int, std::string, double> t1(3, "Kitty", 2.7); int age;
std::string name;
double weight;
std::tie(age, name, weight) = t1;std::cout << "Name: " << name << ", Age: " << age << ", Weight: " << weight << " Kg(s)" << std::endl;age = 10; //修改 age 的值不影响 t1
显然,使用具名变量可以提高代码的可读性,毕竟,一个有具体名字的变量比生冷的 std::get<0> 要强多了。但是需要注意,std::tie() 的捆绑效果是单向的,并且是一次性的,std::tie() 之后再修改具名变量的值不会影响关联的元组的值。
如果关联到的时候对某个元素不感兴趣,可以使用 std::ignore 占位符,比如:
std::tuple<int, std::string, double> t1(3, "Kitty", 2.7); int age;
double weight;
std::tie(age, std::ignore, weight) = t1; //只关心年龄和体重,不关心名字
2.1.4 拼接元组
可以使用 std::tuple_cat() 拼接两个元组变量,得到一个更大的元组,看看这个例子:
std::tuple<int, std::string, double> t1(3, "Kitty", 2.7); auto t2 = std::tuple_cat(t1, std::make_tuple("Garfield", "United Kingdom"));assert(std::tuple_size<decltype(t2)>::value == 5);
拼接后 t2 有五个元素,分别是 (3, “Kitty”, 2.7, “Garfield”, “United Kingdom”)。
2.1.5 std::forward_as_tuple()
2.1.1 节提到了在定义 std::tuple<> 的时候可以使用左值引用类型的元组元素,既然能使用左值引用,当然也可以使用右值引用类型。std::forward_as_tuple() 的作用是返回一个 std::tuple<> 对象,其元素类型是给定的函数参数类型对应的右值引用类型。这句话有点难以理解,用这行代码做例子来理解这个函数:
std::tuple<int&&, FooTest&&> k = std::forward_as_tuple(42, FooTest(5));
当我们传递两个值给 std::forward_as_tuple() 方法时,它的返回值类型是对应的 std::tuple<int&&, FooTest&&>。这个方法存在意义是什么呢?当然是为了参数传递的效率。我们用 std::make_tuple() 跟他做个对比,在对比之前,先看看 FooTest 的实现,我们增加了很多打印信息跟踪这个对象实例的构造和销毁:
struct FooTest {FooTest(const FooTest& f){ std::cout << "FooTest(const FooTest&)" << std::endl; }FooTest(FooTest&& f){ std::cout << "FooTest(FooTest&&)" << std::endl; }FooTest(){ std::cout << "FooTest()" << std::endl; }FooTest(int a){ std::cout << "FooTest(int)" << std::endl; }~FooTest(){ std::cout << "~FooTest()" << std::endl; }
};
先来看看 std::make_tuple() 的执行情况,对于这行代码:
auto kk = std::make_tuple(42, FooTest(5));
打印输出结果如下,执行了两次对象的构造和销毁,其中一次右值构造是因为构造函数返回时产生了一个将亡值临时对象:
FooTest(int)
FooTest(FooTest&&)
~FooTest()
~FooTest()
好了,现在看看 std::forward_as_tuple() 是什么情况,同样的代码:
auto kk = std::forward_as_tuple(42, FooTest(5));
对应的打印结果是:
FooTest(int)
~FooTest()
看到了吗?只在 FooTest(5) 调用时产生了一次 FooTest 对象实例的构造,随后这个对象实例被转发出来,最后随着 kk 销毁的时候一起销毁。现在明白这个方法为什么叫 forward_as_tuple() 了吧?因为它的作用和 std::forward() 类似,具有相同的语意。
由此可见,C++ 对效率的追求到了近乎偏执的地步。类似的右值转发对效率提升是非常显著的,如果有恰当设计的函数配合,右值对象可以“一镜到底”:
void print_Tuple(std::tuple<int&&, FooTest&&> pack)
{ std::cout << std::get<0>(pack) << std::endl; }print_Tuple(std::forward_as_tuple(42, FooTest(5)));
输出结果是:
FooTest(int)
42
~FooTest()
你想到了吗?
2.2 C++ 17 的改进
2.2.1 推断指引
std::tuple<> 也支持推断指引,像这样繁琐的代码:
std::tuple<int, std::string, double, std::string, std::string> t10(3, "Kitty", 2.7, "Garfield", "United Kingdom");
可以简化为:
std::tuple t1(3, "Kitty", 2.7, "Garfield", "United Kingdom");
你只负责想象,剩下的交给编译器。
2.2.2 结构化绑定
使用 std::tie() 可以将元组内的元素关联到一些具名变量上,提高代码的可读性,但是 std::tie() 的使用并不友好,变量需要提前定义好,写代码很繁琐。C++ 17 引入的结构化绑定语法也适用于 std::tuple<>,使用结构化绑定可以简化代码的实现,2.1.3 节的例子可以这样简单地实现:
std::tuple<int, std::string, double> t1(3, "Kitty", 2.7); auto [age, name, weight] = t1; //无需事先声明 age, name 和 weight
前面提到过,std::tie() 关联具名变量是单向的一次性动作,结构化绑定虽然也是一次性动作,但是可以通过引用绑定方式修改被关联对象实例的值,比如:
std::tuple<int, std::string, double> t1(3, "Kitty", 2.7); auto& [age, name, weight] = t1; //引用绑定
age = 4; //同时修改了 t1 的值
assert(std::get<0>(t1) == 4);
除此之外,std::tie() 还有一个局限,那就是它只能用于关联到一个左值类型对象实例,不能用于右值,但是结构化绑定可以,来看一个函数返回值的例子:
std::tuple<int, std::string, double> GetInfo(const std::string& name) {return std::make_tuple(42, "Simon", 108.2);
}int age;
std::string name;
double weight;
std::tie<age, name, weight> = GetInfo("Kitty"); //错误,函数返回值不是左值auto [aa, nn, ww] = GetInfo("Kitty"); //OK,结构化绑定可以
使用结构化绑定的结果就是 aa、nn 和 ww 分别是对应类型的右值引用类型,没有任何临时对象拷贝的开销,非常 nice。
关注作者的算法专栏
https://blog.csdn.net/orbit/category_10400723.html
关注作者的出版物《算法的乐趣(第二版)》
https://www.ituring.com.cn/book/3180
相关文章:
C++ 的 pair 和 tuple
1 std::pair 1.1 C 98 的 std::pair 1.1.1 std::pair 的构造 C 的二元组 std::pair<> 在 C 98 标准中就存在了,其定义如下: template<class T1, class T2> struct pair;std::pair<> 是个类模板,它有两个成员&#x…...
抢十八游戏
前言 我国民国一直流传着一个名叫“抢十八”的抢数游戏:参与游戏的两人从1开始轮流报数,每次至少报1个数,最多报2个数,每人报的每个数不得与自已报过的或对方报过的重复,也不得跳过任何一个数。谁先报到18,…...
从玩具到工业控制--51单片机的跨界传奇【2】
咱们在上一篇博客里面讲解了什么是单片机《单片机入门》,让大家对单片机有了初步的了解。我们今天继续讲解一些有关单片机的知识,顺便也讲解一下我们单片机用到的C语言知识。如果你对C语言还不太了解的话,可以看看博主的C语言专栏哟ÿ…...
LLM实现视频切片合成 前沿知识调研
1.相关产品 产品链接腾讯智影https://zenvideo.qq.com/可灵https://klingai.kuaishou.com/即梦https://jimeng.jianying.com/ai-tool/home/Runwayhttps://aitools.dedao.cn/ai/runwayml-com/Descripthttps://www.descript.com/?utm_sourceai-bot.cn/Opus Cliphttps://www.opu…...
学习threejs,使用FlyControls相机控制器
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.FlyControls 相机控制…...
wordpress 房产网站筛选功能
自定义分类法创建 add_action( init, ashu_post_type ); function ashu_post_type() {register_taxonomy(province,post,array(label => 省,rewrite => array( slug => province ),hierarchical => true));register_taxonomy(city,post,array(label => 市,rewr…...
SQL面试题2:留存率问题
引言 场景介绍: 在互联网产品运营中,用户注册量和留存率是衡量产品吸引力和用户粘性的关键指标,直接影响产品的可持续发展和商业价值。通过分析这些数据,企业可以了解用户行为,优化产品策略,提升用户体验…...
Redis是单线程还是多线程?
大家好,我是锋哥。今天分享关于【Redis是单线程还是多线程?】面试题。希望对大家有帮助; Redis是单线程还是多线程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis是 单线程 的。 尽管Redis的处理是单线程的&a…...
mysql 变量,流程控制与游标
第16章_变量,流程控制与游标 1.变量 分为系统变量和用户自定义变量 1.1系统变量 1.1.1系统变量分类 系统变量分为全局系统变量以及会话系统变量 查看所有全局变量 SHOW GLOBAL VARIABLES 查看所有会话变量 SHOW SESSION VARIABLESor SHOW VARIABLES #默认是会话变量 …...
Java配置log4j日志打印
1. 引入依赖 <dependencies><!-- Log4j 2依赖 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>1.2.14</version> <!-- 可以根据需要修改版本 --></…...
什么是SQL?
什么是SQL? SQL(Structured Query Language,结构化查询语言)是一种用于与关系型数据库进行交互的标准编程语言。SQL 是设计用于管理和操作关系型数据库的语言,主要用于查询、插入、更新、删除和定义数据结构。SQL 是关…...
Linux 机器学习
Linux 机器学习是指在 Linux 操作系统环境下进行机器学习相关的开发、训练和应用。 具体步骤 环境搭建: 选择合适的 Linux 发行版:如 Ubuntu、Fedora、Arch Linux 等。Ubuntu 因其易用性和丰富的软件包管理系统,适合初学者;Fed…...
HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部
HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载 效果展示 使用方法 import LoadingText from "../components/LoadingText" import PageToRefresh from "../components/PageToRefresh" import FooterBar from "../components/…...
第27章 汇编语言--- 设备驱动开发基础
汇编语言是低级编程语言的一种,它与特定的计算机架构紧密相关。在设备驱动开发中,汇编语言有时用于编写性能关键的部分或直接操作硬件,因为它是接近机器语言的代码,可以提供对硬件寄存器和指令集的直接访问。 要展开源代码详细叙…...
sosadmin相关命令
sosadmin命令 以下是本人翻译的官方文档,如有不对,还请指出,引用请标明出处。 原本有个对应表可以跳转的,但是CSDN的这个[](#)跳转好像不太一样,必须得用html标签,就懒得改了。 sosadmin help 用法 sosadm…...
【git】-初始git
学习资源推荐- 标签管理 - Git教程 - 廖雪峰的官方网站 一、什么是版本控制? 二、Git的安装 三、掌握Linux常用命令 四、Git基本操作 1、提交代码 2、查看历史提交 3、版本回退 一、什么是版本控制? 版本控制是一种用于记录文件或项目内容变化的系…...
JAVA之单例模式
单例模式(Singleton Pattern)是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。在软件设计中,单例模式常用于控制对资源的访问,例如数据库连接、线程池等。以下是单例模式的详…...
无人机数据集,支持YOLO,COCO json,PASICAL VOC xml格式的标注,正确识别率可达到95.7%,10000张原始图片
无人机数据集,支持YOLO,COCO json,PASICAL VOC xml格式的标注,正确识别率可达到95.7%,10000张原始图片 下载地址: 标注好的数据集下载地址: yolo v11: https://download.csdn.net/download/p…...
Linux:进程概念(三.详解进程:进程状态、优先级、进程切换与调度)
目录 1. Linux中的进程状态 1.1 前台进程和后台进程 运行状态 睡眠状态 磁盘休眠状态 停止状态 kill指令—向进程发送信号 死亡状态 2. 僵尸进程 2.1 僵尸状态 2.2 僵尸进程 2.3 僵尸进程危害 3. 孤儿进程 4. 进程的优先级 概念 查看进程优先级 PRI(…...
stack和queue专题
文章目录 stack最小栈题目解析代码 栈的压入弹出序列题目解析代码 queue二叉树的层序遍历题目解析代码 stack stack和queue都是空间适配器 最小栈 最小栈的题目链接 题目解析 minst是空就进栈,或者是val < minst.top()就进栈 代码 class MinStack { public:M…...
一 rk3568 Android 11固件开发环境搭建 (docker)
一 目标 搭建 rk3568 android 系统内核 及固件开发编译调试环境, 支持开发环境导出分享 基于荣品 rk3568 核心板 系统环境: ubuntu22.04 /ubuntu20.04 64位桌面版 编译环境: docker + ubuntu20.04 , 独立的容器隔离环境,不受系统库版本冲突等影响,无性能损耗, 可…...
2025年华数杯国际赛B题论文首发+代码开源 数据分享+代码运行教学
176项指标数据库 任意组合 千种组合方式 14页纯图 无水印可视化 63页无附录正文 3万字 1、为了方便大家阅读,全文使用中文进行描述,最终版本需自行翻译为英文。 2、文中图形、结论文字描述均为ai写作,可自行将自己的结果发给ai,…...
三小时深度学习PyTorch
【对新手非常友好】三小时深度学习PyTorch快速入门!包教会你的! --人工智能/深度学习/pytorch_哔哩哔哩_bilibili从头开始,把概率论、统计、信息论中零散的知识统一起来_哔哩哔哩_bilibili从编解码和词嵌入开始,一步一步理解Trans…...
朴素贝叶斯分类器
一、生成模型(学习)(Generative Model) vs 判别模型(学习)(Discriminative Model) 结论:贝叶斯分类器是生成模型 1、官方说明 生成模型对联合概率 p(x, y)建模&#x…...
商用车电子电气零部件电磁兼容条件和试验(2)—术语和定义
写在前面 本系列文章主要讲解商用车电子/电气零部件或系统的传导抗干扰、传导发射和辐射抗干扰、电场辐射发射以及静电放电等试验内容及要求,高压试验项目内容及要求。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 目录 商用车电子电气…...
SimpleFOC01|基于STM32F103+CubeMX,移植核心的common代码
导言 如上图所示,进入SimpleFOC官网,点击Github下载源代码。 如上图所示,找到仓库。 comom代码的移植后,simpleFOC的移植算是完成一大半。simpleFOC源码分为如下5个部分,其中communication是跟simpleFOC上位机通讯&a…...
物联网之传感器技术
引言 在数字化浪潮席卷全球的今天,物联网(IoT)已成为推动各行各业变革的重要力量。而物联网传感器,作为物联网感知层的核心技术,更是扮演着不可或缺的角色。它们如同人类的五官,能够感知物理世界中的各种信…...
React:构建用户界面的JavaScript库
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
基于TypeScript封装 `axios` 请求工具详解
TypeScript 项目中,封装一个详细的 axios 请求工具可以提高代码的可维护性、可重用性,并让请求逻辑与业务逻辑分离。以下是一个详细的封装示例,包括请求拦截器、响应拦截器、错误处理、以及类型定义。 1. 安装 Axios 首先,确保你…...
ElasticSearch在Windows环境搭建测试
引子 也持续关注大数据相关内容一段时间,大数据内容很多。想了下还是从目前项目需求侧出发,进行相关学习。Elasticsearch(ES)是位于 Elastic Stack(ELK stack) 核心的分布式搜索和分析引擎。Logstash 和 B…...
通信与网络安全管理之ISO七层模型与TCP/IP模型
一.ISO参考模型 OSI七层模型一般指开放系统互连参考模型 (Open System Interconnect 简称OSI)是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架。 它从低到高分别是…...
高级运维:shell练习2
1、需求:判断192.168.1.0/24网络中,当前在线的ip有哪些,并编写脚本打印出来。 vim check.sh #!/bin/bash# 定义网络前缀 network_prefix"192.168.1"# 循环遍历1-254的IP for i in {1..254}; do# 构造完整的IP地址ip"$network_…...
三相无刷电机控制|FOC理论04 - 克拉克变换 + 帕克变换的最终目标
导言 通过坐标系旋转,将电机中复杂的三相交流信号映射到与转子磁场同步的旋转参考系中,将动态问题转化为静态问题。这种方法的优点在于: 简化了控制逻辑。实现了转矩Iq和磁通Id的解耦。提供了直流量控制的可能性,大大提高了控制效…...
SAP FICO资产模块各元素基本关系总结
文章目录 【SAP系统研究】 #SAP #FICO #资产会计 ①:每个折旧表包含多个折旧范围,折旧范围用于设置资产的平行折旧,如不同的折旧范围可以更新不同的总账,更新不同的科目等。 ②:折旧表是要分配给公司代码的ÿ…...
Elasticsearch快速入门
Elasticsearch是由elastic公司开发的一套搜索引擎技术,它是elastic技术栈中的一部分,提供核心的数据存储、搜索、分析功能 elasticsearch之所以有如此高性能的搜索表现,正是得益于底层的倒排索引技术。那么什么是倒排索引呢? Elasticsearch…...
【Java数据结构】二叉树相关算法
第一题:获取二叉树中结点个数 得到二叉树结点个数,如果结点为空则返回0,然后再用递归计算左树结点个数根结点(1个)右树结点个数。 public int nodeSize(Node root){if (root null)return 0;return nodeSize1(root.l…...
30分钟内搭建一个全能轻量级springboot 3.4 + 脚手架 <1> 5分钟快速创建一个springboot web项目
快速导航 <1> 5分钟快速创建一个springboot web项目 <2> 5分钟集成好最新版本的开源swagger ui,并使用ui操作调用接口 <3> 5分钟集成好druid并使用druid自带监控工具监控sql请求 <4> 5分钟集成好mybatisplus并使用mybatisplus generator自…...
vue3学习日记6 - Layout
最近发现职场前端用的框架大多为vue,所以最近也跟着黑马程序员vue3的课程进行学习,以下是我的学习记录 视频网址: Day2-17.Layout-Pinia优化重复请求_哔哩哔哩_bilibili 学习日记: vue3学习日记1 - 环境搭建-CSDN博客 vue3学…...
1/14 C++
练习:将图形类的获取周长和获取面积函数设置成虚函数,完成多态 再定义一个全局函数,能够在该函数中实现:无论传递任何图形,都可以输出传递的图形的周长和面积 #include <iostream>using namespace std; class Sh…...
【Uniapp-Vue3】页面生命周期onLoad和onReady
一、onLoad函数 onLoad在页面载入时触发,多用于页面跳转时进行参数传递。 我们在跳转的时候传递参数name和age: 接受参数: import {onLoad} from "dcloudio/uni-app"; onLoad((e)>{...}) 二、onReady函数 页面生命周期函数中的onReady其…...
使用 configparser 读取 INI 配置文件
使用 configparser 读取 INI 配置文件 适合于读取 .ini 格式的配置文件。 配置文件示例 (config.ini): [DEFAULT] host localhost port 3306 [database] user admin password secret import configparser# 创建配置解析器 config configparser.ConfigParser()# 读取配…...
类模板的使用方法
目录 类模板的使用方法 1.类模板语法 2.类模板和函数模板区别 3.类模板中成员函数创建时机 4.类函数对象做函数参数 5.类模板和继承 6.类模板成员函数类外实现 7.类模板分文件编写 person.hpp 实现cpp文件: 8.类模板与友元 9.类模板案例 MyArray.hpp …...
docker mysql5.7如何设置不区分大小写
环境 docker部署,镜像是5.7,操作系统是centos 操作方式 mysql 配置文件是放在 /etc/mysql/mysql.conf.d/mysqld.cnf, vim /etc/mysql/mysql.conf.d/mysqld.cnf lower_case_table_names1 重启mysql容器 验证 SHOW VARIABLES LIKE low…...
Docker与虚拟机的区别及常用指令详解
在现代软件开发中,容器化和虚拟化技术已经成为不可或缺的工具。Docker和虚拟机(VM)是两种常见的技术, 它们都可以帮助开发者在不同的环境中运行应用程序。然而,它们的工作原理和使用场景有很大的不同。本文将详细探讨D…...
C#异步和多线程,Thread,Task和async/await关键字--12
目录 一.多线程和异步的区别 1.多线程 2.异步编程 多线程和异步的区别 二.Thread,Task和async/await关键字的区别 1.Thread 2.Task 3.async/await 三.Thread,Task和async/await关键字的详细对比 1.Thread和Task的详细对比 2.Task 与 async/await 的配合使用 3. asy…...
第一次作业三种方式安装mysql(Windows和linux下)作业
在Windows11上安装sever(服务)端和客户端 server端安装 打开官网MySQL 进入到主页 点击DOWMLOAD 进入下载界面 点击下方MySQL Community (GPL) Downloads 进入社区版mysql下载界面 点击 MySQL Community Server 进入server端下载 选择8.4.3LTS&…...
ubuntu官方软件包网站 字体设置
在https://ubuntu.pkgs.org/22.04/ubuntu-universe-amd64/xl2tpd_1.3.16-1_amd64.deb.html搜索找到需要的软件后,点击,下滑, 即可在Links和Download找到相关链接,下载即可, 但是找不到ros的安装包, 字体设…...
深拷贝与浅拷贝
作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习 擅长领域:驱动开发,嵌入式软件开发,BSP开发 作者主页:一个平凡而乐于分享的小比特的个人主页…...
No one knows regex better than me
No one knows regex better than me 代码分析,传了两个参数zero,first,然后$second对两个所传的参数进行了拼接 好比:?zero1&first2 传入后就是: 12 然后对$second进行了正则匹配,匹配所传入的参数是否包含字符串Yeedo|wa…...
scala基础学习(数据类型)-集合
文章目录 集合创建集合isEmpty获取数据添加元素删除元素常见方法交集 &差集 diff --并集 unionto stringto listto Arrayto Map其余常用方法 集合 Scala Set(集合)是没有重复的对象集合,所有的元素都是唯一的。 Scala 集合分为可变的和不可变的集合。 默认情…...