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

C++模板元编程详细教程(之九)

前序文章请看:
C++模板元编程详细教程(之一)
C++模板元编程详细教程(之二)
C++模板元编程详细教程(之三)
C++模板元编程详细教程(之四)
C++模板元编程详细教程(之五)
C++模板元编程详细教程(之六)
C++模板元编程详细教程(之七)
C++模板元编程详细教程(之八)

多选一结构

这一章我们来看看如何编写一个多选一的结构,STL中提供了std::variant,我们就来实现一个简易版。(注意下面我们实现的variant与STL中的是有区别的,但大体思路是相同的,请读者不要以本节的代码参考使用std::variant)。

我们的诉求是,创建一个数据结构,「可能」存放多种类型,但同一时间只能有一种,并且可以在运行期变化为另一种。这里比较容易想到的做法就是用共合体类型存储数据,再加一个用于表示当前哪种数据是生效的index。请看代码:

template <typename T1, typename T2>
class variant {
public:// 针对每种情况的构造variant(const T1 &t1);variant(const T2 &t2);
private:union {T1 t1;T2 t2;} data;int index; // 当前生效的数据序号
};

只不过这样我们很快就会发现很多严重的问题:

  1. 对于任意个数的参数,无法映射到union结构中;
  2. 如果数据类型不含无参构造函数,union结构的构造会报错;
  3. variant的构造函数依赖数据类型的拷贝构造,对于不可拷贝类型来说无法创建。

因此,我们必须换一个思路。既然一开始我们想到用union,主要也是为了内存空间的复用,所以我们只需要自己来维护一片数据空间就好了,以参数类型中长度最大的为准,创建一个缓存空间即可。

template <typename... Types>
class variant {private:void *data = std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index; // 当前生效的数据序号
};

接下来的任务就是,构造函数。由于这里的Types是变参,所以无法穷举,与此同时,我们希望可以就地构造,跳过「拷贝构造」这个阶段,以支持不可拷贝类型的数据,因此必须有一个Index来标识,后面跟变参:

template <typename... Types>
class variant {public:template <size_t Index, typename... Args>variant(Args &&... args); // 大概是这个意思private: void *data = std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index; // 当前生效的数据序号
};

然而,出于语法限制,构造函数用模板生成的话,是无法手动实例化的,例如:

variant<1, int> va; // <1, int>会识别为类型的模板参数,而不是构造函数的模板参数

因此,构造函数的模板参数只能依赖于自动推导,所以,我们就需要提供一个工具,用来「传递」这个Index

template <size_t Index>
struct in_place_index_t {}; // 单纯的静态工具,用于传递Index,没有运行期意义template <size_t Index>
constexpr inline in_place_index_t<Index> in_place_index; // 对应in_place_index_t类型的实例template <typename... Types>
class variant {public:template <size_t Index, typename... Args>variant(const in_place_index_t<Index> &, Args &&... args);private:void *data = std::malloc(std::max(sizeof(Types)...)); int index;
};

然后,构造时,也同样通过in_place_index来构造,传递这个Index

 // 用于测试的类型
struct Test1 {Test1(int, double);
};
struct Test2 {Test1(char, int);
};void Demo() {variant<Test1, Test2> var{in_place_index<0>, 1, 1.5}; // 用于构造Test1类型variant<Test1, Test2> var{in_place_index<1>, 'A', 1}; // 用于构造Test2类型
}

那么接下来的问题就是如何解析了,variant本身的参数是一组typename列表,但构造传进来的是一个Index序号,如何对应呢?相信读者到现在应该已经建立初步的感觉了,没错,递归大法好!

template <size_t Index, typename Head, typename... Args>
struct get_type_by_index : get_type_by_index<Index - 1, Args...> {};template <typename Head, typename... Args>
struct get_type_by_index<0, Head, Args...> {using type = Head;
};// 验证Demo
void Demo() {std::cout << std::is_same_v<typename get_type_by_index<2, int, double, char, void *>::type , char> << std::endl; // 1
}

有了这个工具,我们就可以从类型列表里通过Index取出对应的类型了,以此来完成variant的构造函数:

// 实现构造函数
template <typename... Types>
template <size_t Index, typename... Args>
variant<Types...>::variant(const in_place_index_t<Index> &, Args &&... args): index(Index) {// 先把需要构造的类型拿出来using data_type = typename get_type_by_index<Index, Args...>::type;// 在data处进行就地构造new(data) std::decay_t<data_type>(std::forward<Args>(args)...);
}

最难的构造已经完成了,我们先实现一下周边功能,析构、拷贝构造和赋值函数先放一放,给出一个阶段性的代码:

template <size_t Index>
struct in_place_index_t {}; // 单纯的静态工具,用于传递Index,没有运行期意义template <size_t Index>
constexpr inline in_place_index_t<Index> in_place_index; // 对应in_place_index_t类型的实例template <size_t Index, typename Head, typename... Args>
struct get_type_by_index : get_type_by_index<Index - 1, Args...> {};template <typename Head, typename... Args>
struct get_type_by_index<0, Head, Args...> {using type = Head;
};template <typename... Types>
class variant {public:template <size_t Index, typename... Args>variant(const in_place_index_t<Index> &, Args &&... args);// 获取当前序号int index() const;// 取出数据template <size_t Index>auto get() const -> std::add_lvalue_reference_t<std::decay_t<typename get_type_by_index<Index, Types...>::type>>;private:void *data_ = std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index_; // 当前生效的数据序号
};// 实现构造函数
template <typename... Types>
template <size_t Index, typename... Args>
variant<Types...>::variant(const in_place_index_t<Index> &, Args &&... args): index_(Index) {// 先把需要构造的类型拿出来using data_type = typename get_type_by_index<Index, Args...>::type;// 在data处进行就地构造new(data_) std::decay_t<data_type>(std::forward<Args>(args)...);
}// 获取序号
template <typename... Types>
int variant<Types...>::index() const {return index_;
}// 取出数据(这个功能在std::variant中其实实现在std::get中)
template <typename... Types>
template <size_t Index>
auto variant<Types...>::get() const -> std::add_lvalue_reference_t<std::decay_t<typename get_type_by_index<Index, Types...>::type>> {using data_type = std::decay_t<typename get_type_by_index<Index, Types...>::type>;return *static_cast<data_type *>(data_);
}

接下来我们要攻克的,就是析构、拷贝构造、拷贝赋值这几个问题了,它们的难点在于,没有静态的Index参数可供使用,但还要找到现在数据的类型。就拿析构来说,析构函数并没有静态的Index参数,只有一个运行时的index成员,但我们要找到此时index_成员表示的data_所指向数据的实际类型,然后调用这个类型的析构函数。拷贝构造、拷贝赋值也同样需要先析构现有数据,所以面临同样的问题。

这种情况怎么办呢?类比前面章节介绍的元组的动态get方法,我们这里也采取「静态穷举生成所有可能情况代码」的方法。

以析构为例,在析构时,要根据index_去判断当前保存的数据是哪一种类型的,然后去调用对应类型的析构函数。因此,我们需要在静态期就提供每一种类型的析构方法,然后将它们和类型的Index关联起来,这样在运行时就可以调用了。

template <typename... Types>
class variant {public:// 无关代码暂时省略 ~variant(); // 析构函数private:void *data_ = std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template <typename Type>void destory_data();
};template <typename... Types>
template <typename Type>
void variant<Types...>::destory_data() {// 用data_指针按照对应的类型调用析构函数static_cast<std::add_pointer_t<Type>>(data_)->~Type();
}// 实现析构函数
template <typename... Types>
variant<Types...>::~variant() {// 析构函数中,把所有的index对应的destory_data保存下来(编译期完成这样一个映射表)std::array<void (variant<Types...>::*)(), sizeof...(Types)> destory_functions {&variant<Types...>::destory_data<Types>... // 按照类型参数展开,把对应的destory_data实例的函数指针保存下来};// 到了运行期,根据当前实际的index_值,选择对应的析构方法if (data_ != nullptr) {(this->*destory_functions.at(index_))();std::free(data_);}
}

对于拷贝构造、拷贝赋值来说,首先把原来的内容析构调,然后再根据被复制方的index_,来调用对应的构造函数。于是,我们还需要补充一个index_与构造函数的映射表,思路和析构完全相同:

template <typename... Types>
class variant {public:// 无关代码先省略variant(const variant &va);private:void *data_ = std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template <typename Type>void destory_data();// 生成每一个Type下对应类型的构造方法// 注意,由于我们要把生成的所有方法保存在数组中,因此函数类型需要一致,所以参数用泛型指针template <typename Type>void create_data(const void *obj);
};template <typename... Types>
template <typename Type>
void variant<Types...>::create_data(const void *obj) {// 用data_指针按照对应的类型调用拷贝构造new(data_) Type(*static_cast<const Type *>(obj));
}template <typename... Types>
variant<Types...>::variant(const variant &va): index_(va.index_) {// 静态期保存所有类型的构造函数std::array<void (variant<Types...>::*)(const void *), sizeof...(Types)> create_functions {&variant<Types...>::create_data<Types>...};// 动态时根据index_调用对应的构造(this->*create_functions.at(index_))(va.data_);
}

有了这样的思路,那么我们就可以完善所有的代码了,拷贝赋值函数可以按照相同的方法写出来了(只不过需要先析构,再重新构造)。下面给出整个项目的完整代码:

// 辅助工具
template <size_t Index>
struct in_place_index_t {}; // 单纯的静态工具,用于传递Index,没有运行期意义template <size_t Index>
constexpr inline in_place_index_t<Index> in_place_index; // 对应in_place_index_t类型的实例template <size_t Index, typename Head, typename... Args>
struct get_type_by_index : get_type_by_index<Index - 1, Args...> {};template <typename Head, typename... Args>
struct get_type_by_index<0, Head, Args...> {using type = Head;
};// variant结构的声明
template <typename... Types>
class variant {public:template <size_t Index, typename... Args>variant(const in_place_index_t<Index> &, Args &&... args);variant(const variant &va);variant(variant &&va);~variant();variant &operator =(const variant &va);variant &operator =(variant &&va);// 获取当前序号int index() const;// 取出数据template <size_t Index>auto get() const -> std::add_lvalue_reference_t<std::decay_t<typename get_type_by_index<Index, Types...>::type>>;private:void *data_ = std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template <typename Type>void destory_data();// 生成每一个Type下对应类型的构造方法template <typename Type>void create_data(const void *obj);
};// 实现构造函数
template <typename... Types>
template <size_t Index, typename... Args>
variant<Types...>::variant(const in_place_index_t<Index> &, Args &&... args): index_(Index) {using data_type = typename get_type_by_index<Index, Args...>::type;new(data_) std::decay_t<data_type>(std::forward<Args>(args)...);
}// 实现析构函数
template <typename... Types>
variant<Types...>::~variant() {// 析构函数中,把所有的index对应的destory_data保存下来(编译期完成这样一个映射表)std::array<void (variant::* const)(), sizeof...(Types)> destory_functions {&variant::destory_data<Types>...};// 到了运行期,根据当前实际的index_值,选择对应的析构方法if (data_ != nullptr) {(this->*destory_functions.at(index_))();std::free(data_);}
}// 实现拷贝构造函数
template <typename... Types>
variant<Types...>::variant(const variant &va): index_(va.index_) {// 静态期保存所有类型的构造函数std::array<void (variant<Types...>::*)(const void *), sizeof...(Types)> create_functions {&variant<Types...>::create_data<Types>...};// 动态时根据index_调用对应的构造(this->*create_functions.at(index_))(va.data_);
}// 实现拷贝赋值函数
template <typename... Types>
variant<Types...> &variant<Types...>::operator =(const variant &va) {// 先析构现有数据std::array<void (variant<Types...>::*)(), sizeof...(Types)> destory_functions {&variant<Types...>::destory_data<Types>...};(this->*destory_functions.at(index_))();// 再重新构造std::array<void (variant<Types...>::*)(const void *), sizeof...(Types)> create_functions {&variant<Types...>::create_data<Types>...};(this->*create_functions.at(index_))(va.data_);return *this;
}// 实现移动构造函数
template <typename... Types>
variant<Types...>::variant(variant &&va): index_(va.index_), data_(va.index_) {// 上面直接浅拷贝即可,然后把被移动的data_置空va.data_ = nullptr;va.index_ = -1; // 标记为不合法值
}// 实现移动赋值函数
template <typename... Types>
variant<Types...> &variant<Types...>::operator =(variant &&va) {// 先析构现有数据std::array<void (variant<Types...>::*)(), sizeof...(Types)> destory_functions {&variant<Types...>::destory_data<Types>...};(this->*destory_functions.at(index_))();// 再浅拷贝data_ = va.data_;index_ = va.index_;// 把被移动的data_置空va.data_ = nullptr;va.index_ = -1; // 标记为不合法值return *this;
}// 私有方法的实现
template <typename... Types>
template <typename Type>
void variant<Types...>::create_data(const void *obj) {// 用data_指针按照对应的类型调用拷贝构造new(data_) Type(*static_cast<const Type *>(obj));
}template <typename... Types>
template <typename Type>
void variant<Types...>::destory_data() {// 用data_指针按照对应的类型调用析构函数static_cast<std::add_pointer_t<Type>>(data_)->~Type();
}// 公有方法的实现
// 获取序号
template <typename... Types>
int variant<Types...>::index() const {return index_;
}// 取出数据(这个功能在std::variant中其实实现在std::get中)
template <typename... Types>
template <size_t Index>
auto variant<Types...>::get() const -> std::add_lvalue_reference_t<std::decay_t<typename get_type_by_index<Index, Types...>::type>> {using data_type = std::decay_t<typename get_type_by_index<Index, Types...>::type>;return *static_cast<data_type *>(data_);
}

小结

这一篇以一个「多选一」结构为例,带大家体验了一下模板元编程的实际使用方式,当然,这还没完,下一篇我们会针对这个多选一结构写一个「成员访问器」,会用到更多模板元编程的技巧。

相关文章:

C++模板元编程详细教程(之九)

前序文章请看&#xff1a; C模板元编程详细教程&#xff08;之一&#xff09; C模板元编程详细教程&#xff08;之二&#xff09; C模板元编程详细教程&#xff08;之三&#xff09; C模板元编程详细教程&#xff08;之四&#xff09; C模板元编程详细教程&#xff08;之五&…...

PhysioNet2017分类的代码实现

PhysioNet2017数据集介绍可参考文章&#xff1a;https://wendy.blog.csdn.net/article/details/128686196。本文主要介绍利用PhysioNet2017数据集对其进行分类的代码实现。 目录一、数据集预处理二、训练2.1 导入数据集并进行数据裁剪2.2 划分训练集、验证集和测试集2.3 设置训…...

正大期货本周财经大事抢先看

美国1月CPI、Fed 等央行官员谈话 美国1月超强劲的非农就业人口&#xff0c;让投资人开始上修对这波升息循环利率顶点的预测&#xff0c;也使本周二 (14 日) 的美国 1月 CPI 格外受关注。 介绍正大国际期货主账户对比国内期货的优势 ​第一点&#xff1a;权限都在主账户 例如…...

html+css综合练习一

文章目录一、小米注册页面1、要求2、案例图3、实现效果3.1、index.html3.2、style.css二、下午茶页面1、要求2、案例图3、index.html4、style.css三、法国巴黎页面1、要求2、案例图3、index.html4、style.css一、小米注册页面 1、要求 阅读下列说明、效果图&#xff0c;进行静…...

安装jdk8

目录标题一、下载地址&#xff08;一&#xff09;Linux下载&#xff08;二&#xff09;Win下载二、安装&#xff08;一&#xff09;Linux&#xff08;二&#xff09;Win三、卸载&#xff08;一&#xff09;Linux&#xff08;二&#xff09;Win一、下载地址 jdk8最新版 jdk8其他…...

二分法心得

原教程见labuladong 首先&#xff0c;我们建议左右区间全部用闭区间。那么第一个搜索区间&#xff1a;left0; rightlen-1; 进入while循环&#xff0c;结束条件是right<left。 然后求mid&#xff0c;如果nums[mid]的值比target大&#xff0c;说明target在左边&#xff0c;…...

Linux安装Docker完整教程

背景最近接手了几个项目&#xff0c;发现项目的部署基本上都是基于Docker的&#xff0c;幸亏在几年前已经熟悉的Docker的基本使用&#xff0c;没有抓瞎。这两年随着云原生的发展&#xff0c;Docker在云原生中的作用使得它也蓬勃发展起来。今天这篇文章就带大家一起实现一下在Li…...

备份基础知识

备份策略可包括&#xff1a;– 整个数据库&#xff08;整个&#xff09;– 部分数据库&#xff08;部分&#xff09;• 备份类型可指示包含以下项&#xff1a;– 所选文件中的所有数据块&#xff08;完全备份&#xff09;– 只限自以前某次备份以来更改过的信息&#xff08;增量…...

C++学习记录——팔 内存管理

文章目录1、动态内存管理2、内存管理方式operator new operator delete3、new和delete的实现原理1、动态内存管理 C兼容C语言关于内存分配的语法&#xff0c;而添加了C独有的东西。 //int* p1 (int*)malloc(sizeof(int));int* p1 new int;new是一个操作符&#xff0c;C不再需…...

Spring事务失效原因分析解决

文章目录1、方法内部调用2、修饰符3、非运行时异常4、try…catch捕获异常5、多线程调用6、同时使用Transactional和Async7、错误使用事务传播行为8、使用的数据库不支持事务9、是否开启事务支持在工作中&#xff0c;经常会碰到一些事务失效的坑&#xff0c;基于遇到的情况&…...

4个月的测试经验,来面试就开口要17K,面试完,我连5K都不想给他.....

2021年8月份我入职了深圳某家创业公司&#xff0c;刚入职还是很兴奋的&#xff0c;到公司一看我傻了&#xff0c;公司除了我一个测试&#xff0c;公司的开发人员就只有3个前端2个后端还有2个UI&#xff0c;在粗略了解公司的业务后才发现是一个从零开始的项目&#xff0c;目前啥…...

python学习之pyecharts库的使用总结

pyecharts官方文档&#xff1a;https://pyecharts.org//#/zh-cn/ 【1】Timeline 其是一个时间轴组件&#xff0c;如下图红框所示&#xff0c;当点击红色箭头指向的“播放”按钮时&#xff0c;会呈现动画形式展示每一年的数据变化。 data格式为DataFrame&#xff0c;数据如下图…...

【taichi】利用 taichi 编写深度学习算子 —— 以提取右上三角阵为例

本文以取 (bs, n, n) 张量的右上三角阵并展平为向量 (bs, n*(n1)//2)) 为例&#xff0c;展示如何用 taichi 编写深度学习算子。 如图&#xff0c;要把形状为 (bs,n,n)(bs,n,n)(bs,n,n) 的张量&#xff0c;转化为 (bs,n(n1)2)(bs,\frac{n(n1)}{2})(bs,2n(n1)​) 的向量。我们先写…...

二进制 k8s 集群下线 worker 组件流程分析和实践

文章目录[toc]事出因果个人思路准备实践当前 worker 节点信息将节点标记为不可调度驱逐节点 pod将 worker 节点从 k8s 集群踢出下线 worker 节点相关组件事出因果 因为之前写了一篇 二进制 k8s 集群下线 master 组件流程分析和实践&#xff0c;所以索性再写一个 worker 节点的缩…...

Bean的六种作用域

限定程序中变量的可用范围叫做作用域&#xff0c;Bean对象的作用域是指Bean对象在Spring整个框架中的某种行为模式~~ Bean对象的六种作用域&#xff1a; singleton&#xff1a;单例作用域&#xff08;默认&#xff09; prototype&#xff1a;原型作用域&#xff08;多例作用域…...

Http发展历史

1 缘起 有一次&#xff0c;听到有人在议论招聘面试的人员&#xff0c; 谈及应聘人员的知识深度&#xff0c;说&#xff1a;问了一些关于Http的问题&#xff0c;如Http相关结构、网络结构等&#xff0c; 然后又说&#xff0c;问没问相关原理、来源&#xff1f; 我也是有些困惑了…...

高级Java程序员必备的技术点,你会了吗?

很多程序员在入行之后的前一两年&#xff0c;快速学习到了做项目常用的各种技术之后&#xff0c;便进入了技术很难寸进的平台期。反正手里掌握的一些技术对于应付普通项目来说&#xff0c;足够用了。因此也会缺入停滞&#xff0c;最终随着年龄的增长&#xff0c;竞争力不断下降…...

【暴力量化】查找最优均线

搜索逻辑 代码主要以支撑概率和压力概率来判断均线的优劣 判断为压力&#xff1a; 当日线与测试均线发生金叉或即将发生金叉后继续下行 判断为支撑&#xff1a; 当日线与测试均线发生死叉或即将发生死叉后继续上行 判断结果的天数&#xff1a; 小于6日均线&#xff0c;用金叉或…...

Java读取mysql导入的文件时中文字段出现�??的乱码如何解决

今天在写程序时遇到了一个乱码问题&#xff0c;困扰了好久&#xff0c;事情是这样的&#xff0c; 在Mapper层编写了查询语句&#xff0c;然后服务处调用&#xff0c;结果控制器返回一堆乱码 然后查看数据源头处&#xff1a; 由重新更改解码的字符集&#xff0c;在数据库中是正…...

k8s核心概念—Pod Controller Service介绍——20230213

文章目录一、Pod1. pod概述2. pod存在意义3. Pod实现机制4. pod镜像拉取策略5. pod资源限制6. pod重启机制7. pod健康检查8. 创建pod流程9. pod调度二、Controller1. 什么是Controller2. Pod和Controller关系3. deployment应用场景4. 使用deployment部署应用&#xff08;yaml&a…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...