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

C++类型参数技术以及常见的类型擦除容器

文章目录

  • 一、类型擦除的作用
  • 二、常见的类型擦除容器
    • 1.std::any
    • 2.std::function
    • 3.std::shared_ptr\<void\>和 std::unique_ptr\<void\>
    • 4.总结
  • 三、实现一个any
  • 参考

类型擦除(Type Erasure)是一种编程技术,通过它可以在运行时存储和操作不同类型的对象,同时隐藏这些类型的具体信息。C++ 标准库中提供了几种常见的类型擦除容器,用于存储和操作多态对象。这些容器包括但不限于以下几种:

  • std::any(C++17 引入)
  • std::function
  • std::shared_ptr 和 std::unique_ptr
  • boost::any(Boost 库)
  • boost::function(Boost 库)

一、类型擦除的作用

类型擦除就是将原有类型消除或者隐藏。

为什么要擦除类型?因为很多时候我不关心具体类型是什么或者根本就不需要这个类型,通过类型擦除我们可以获取很多好处,比如使得我们的程序有更好的扩展性、还能消除耦合以及消除一些重复行为,使程序更加简洁高效。

归纳一下c++中类型擦除方式主要有如下五种:

  • 第一种:通过多态来擦除类型
  • 第二种:通过模板来擦除类型
  • 第三种:通过某种容器来擦除类型
  • 第四种:通过某种通用类型来擦除类型
  • 第五种:通过闭包来擦除类型

第一种类型隐藏的方式最简单也是我们经常用的,通过将派生类型隐式转换成基类型,再通过基类去多态的调用行为,在这种情况下,我不用关心派生类的具体类型,我只需要以一种统一的方式去做不同的事情,所以就把派生类型转成基类型隐藏起来,这样不仅仅可以多态调用还使我们的程序具有良好的可扩展性。然而这种方式的类型擦除仅仅是部分的类型擦除,因为基类型仍然存在,而且这种类型擦除的方式还必须是继承方式的才可以,而且继承使得两个对象强烈的耦合在一起了,正是因为这些缺点,通过多态来擦除类型的方式有较多局限性效果也不好。

时我们通过第二种方式擦除类型,以解决第一种方式的一些缺点。通过模板来擦除类型,本质上是把不同类型的共同行为进行了抽象,这时不同类型彼此之间不需要通过继承这种强耦合的方式去获得共同的行为了,仅仅是通过模板就能获取共同行为,降低了不同类型之间的耦合,是一种很好的类型擦除方式。然而,第二种方式虽然降低了对象间的耦合,但是还有一个问题没解决,就是基本类型始终需要指定,并没有消除基本类型,例如,我不可能把一个T本身作为容器元素,必须在容器初始化时就要知名这个T是具体某个类型。

需要注意的是,第四和第五种方式虽然解决了第三种方式不能彻底消除基本类型的缺点,但是还存一个缺点,就是取值的时候仍然依赖于具体类型,无论我是通过get还是any_cast,我都要T的具体类型,这在某种情况下仍然有局限性。

eg:我有A、B、C、D四种结构体,每个结构体中有某种类型的指针,名称且称为info,我现在提供了返回这些结构体的四个接口供外接使用,有可能是c#或者dephi调用这些接口,由于结构体中的info指针是我分配的内存,所以我必须提供释放这些指针的接口。代码如下:

struct A
{int* info;int id;
};struct B
{double* info;int id;
};struct C
{char* info;int id;
};struct D
{float* info;int id;
};//对外提供的删除接口
void DeleteA(A& t)
{delete t.info;
}void DeleteB(B& t)
{delete t.info;
}void DeleteC(C& t)
{delete t.info;
}void DeleteD(D& t)
{delete t.info;
}

大家可以看到,增加的四个删除函数内部都是重复代码,本来通过模板函数一行搞定,但是没办法,c#可没有c++的模板,还得老老实实的提供这些重复行为的接口,而且这种方式还有个坏处就是每增加一种类型就得增加一个重复的删除接口,怎么办?能统一成一个删除接口吗?可以,一个可行的办法就是将分配的内存通过一个ID关联并保存起来,让外接传一个ID,告诉我要删那块内存,新的统一删除函数可能是这样:

//内部将分配的内存存到map中,让外面传ID,内部通过ID去删除对应的内存块
map<int, T> mapT;template<typename R, typename T>
R GetT()
{R result{1,new T()};mapT.insert(std::pair<int, T>(1, R)); return result;
}//通过ID去关联我分配的内存块,外面传ID,内部通过ID去删除关联的内存块
void DeleteT(const int& id)
{R t = mapT[id]->second();delete t.info;
}

很遗憾,上面的代码编译不过,因为,map<int, T> mapT只能保存一种类型的对象,无法把分配的不同类型的对象保存起来,我们可以通过方式三和方式四,用variant或者any去擦除类型,解决T不能代表多种类型的问题,第一个问题解决。但是还有第二个问题,DeleteT时,从map中返回的variant或者any,无法取出来,因为接口函数中没有类型信息,而取值方法get和any_cast都需要一个具体类型。似乎进入了死胡同,无法只提供一个删除接口了。但是办法总还是有的。

方式五隆重登场了,看似无解的问题,通过方式五就能解决了。通过闭包来擦除类型很好很强大。

闭包也可以称为匿名函数或者lamda表达式,c++11中的lamda表达式就是c++中的闭包,c++11引入lamda,实际上引入了函数式编程的概念,函数式编程有很多优点,使代码更简洁,而且声明式的编码方式更贴近人的思维方式。函数式编程在更高的层次上对不同类型的公共行为进行了抽象,从而使我们不必去关心具体类型。

std::map < int, std::function <void()>> m_freeMap; //保存返回出去的内存块template<typename R, typename T>
R GetResult()
{R result = GetTable<R, T>();    m_freeMap.insert(std::make_pair(result.sequenceId, [this, result]{FreeResult(result);        }));
}bool FreeResultById(int& memId){auto it = m_freeMap.find(memId);if (it == m_freeMap.end())return false;it->second(); //delete by lamdam_freeMap.erase(memId);return true;}

通过闭包去擦除类型,可以解决前面四种擦除方式遇到的问题

二、常见的类型擦除容器

1.std::any

std::any 是 C++17 引入的一种类型擦除容器,可以存储任何类型的值,并在运行时决定具体类型。

#include <any>
#include <iostream>
#include <string>int main() {std::any a = 42;std::cout << std::any_cast<int>(a) << std::endl;a = std::string("Hello, World!");std::cout << std::any_cast<std::string>(a) << std::endl;return 0;
}

2.std::function

std::function 是一种通用的多态函数封装器,可以存储和调用任何可调用对象,包括函数指针、lambda 表达式、绑定表达式或其他函数对象。

#include <functional>
#include <iostream>void foo() {std::cout << "foo" << std::endl;
}int main() {std::function<void()> f = foo;f();f = []() { std::cout << "lambda" << std::endl; };f();return 0;
}

3.std::shared_ptr<void>和 std::unique_ptr<void>

智能指针 std::shared_ptr 和 std::unique_ptr 可以通过指向 void 类型来实现类型擦除,从而存储任意类型的对象。

#include <iostream>
#include <memory>int main() {std::shared_ptr<void> p = std::make_shared<int>(42);std::cout << *std::static_pointer_cast<int>(p) << std::endl;p = std::make_shared<std::string>("Hello, World!");std::cout << *std::static_pointer_cast<std::string>(p) << std::endl;return 0;
}

4.总结

这些类型擦除容器在需要存储和操作多态对象时非常有用,可以在运行时决定具体类型,而不需要在编译时知道类型的具体信息。根据具体需求和项目依赖,可以选择使用标准库或 Boost 库提供的类型擦除容器。

三、实现一个any

any的设计思路:Any内部维护了一个基类指针,通过基类指针擦除具体类型,any_cast时再通过向下转型获取实际数据。当转型失败时打印详情。

any能容纳所有类型的数据,因此当赋值给any时,需要将值的类型擦除才行,即以一种通用的方式保存所有类型的数据。这里可以通过继承去擦除类型,基类是不含模板参数的,派生类中才有模板参数,这个模板参数类型正是赋值的类型,在赋值时,将创建的派生类对象赋值给基类指针,基类的派生类中携带了数据类型,基类只是原始数据的一个占位符,通过多态,它擦除了原始数据类型,因此,任何数据类型都可以赋值给他,从而实现了能存放所有类型数据的目标。

当取数据时需要向下转换成派生类型来获取原始数据,当转换失败时打印详情,并抛出异常。

由于any赋值时需要创建一个派生类对象,所以还需要管理该对象的生命周期,这里用unique_ptr智能指针去管理对象的生命周期。

#include <iostream>
#include <string>
#include <memory>
#include <typeindex>
struct Any
{Any(void) : m_tpIndex(std::type_index(typeid(void))){}Any(const Any& that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {}Any(Any && that) : m_ptr(std::move(that.m_ptr)), m_tpIndex(that.m_tpIndex) {}//创建智能指针时,对于一般的类型,通过std::decay来移除引用和cv符,从而获取原始类型template<typename U, class = typename std::enable_if<!std::is_same<typename std::decay<U>::type, Any>::value, U>::type> Any(U && value) : m_ptr(new Derived < typename std::decay<U>::type>(forward<U>(value))),m_tpIndex(type_index(typeid(typename std::decay<U>::type))){}bool IsNull() const { return !bool(m_ptr); }template<class U> bool Is() const{return m_tpIndex == type_index(typeid(U));}//将Any转换为实际的类型template<class U>U& AnyCast(){if (!Is<U>()){cout << "can not cast " << typeid(U).name() << " to " << m_tpIndex.name() << endl;throw bad_cast();}auto derived = dynamic_cast<Derived<U>*> (m_ptr.get());return derived->m_value;}Any& operator=(const Any& a){if (m_ptr == a.m_ptr)return *this;m_ptr = a.Clone();m_tpIndex = a.m_tpIndex;return *this;}private:struct Base;typedef std::unique_ptr<Base> BasePtr;struct Base{virtual ~Base() {}virtual BasePtr Clone() const = 0;};template<typename T>struct Derived : Base{template<typename U>Derived(U && value) : m_value(forward<U>(value)) { }BasePtr Clone() const{return BasePtr(new Derived<T>(m_value));}T m_value;};BasePtr Clone() const{if (m_ptr != nullptr)return m_ptr->Clone();return nullptr;}BasePtr m_ptr;std::type_index m_tpIndex;
};

测试:

void TestAny()
{Any n;    auto r = n.IsNull();//truestring s1 = "hello";n = s1;n = "world";n.AnyCast<int>(); //can not cast int to stringAny n1 = 1;n1.Is<int>(); //true
}

其他:

template<typename T>
T& any_cast(any& aAny)
{if (typeid(T) == aAny.type_){return *static_cast<T*>(aAny.data_);}else{throw std::bad_any_cast{};}
}

参考

  • (原创)c++中的类型擦除
  • How std::any Works

相关文章:

C++类型参数技术以及常见的类型擦除容器

文章目录 一、类型擦除的作用二、常见的类型擦除容器1.std::any2.std::function3.std::shared_ptr\<void\>和 std::unique_ptr\<void\>4.总结 三、实现一个any参考 类型擦除&#xff08;Type Erasure&#xff09;是一种编程技术&#xff0c;通过它可以在运行时存储…...

SpringBoot如何缓存方法返回值?

Why&#xff1f; 为什么要对方法的返回值进行缓存呢&#xff1f; 简单来说是为了提升后端程序的性能和提高前端程序的访问速度。减小对db和后端应用程序的压力。 一般而言&#xff0c;缓存的内容都是不经常变化的&#xff0c;或者轻微变化对于前端应用程序是可以容忍的。 否…...

C#的web项目ASP.NET

添加实体类和控制器类 using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace WebApplication1.Models {public class Company{public string companyCode { get; set; }public string companyName { get; set; }public string com…...

Spring MVC 源码分析之 DispatcherServlet#getHandlerAdapter 方法

前言&#xff1a; 前面我们分析了 Spring MVC 的工作流程源码&#xff0c;其核心是 DispatcherServlet#doDispatch 方法&#xff0c;我们前面分析了获取 Handler 的方法 DispatcherServlet#getHandler 方法&#xff0c;本篇我们重点分析一下获取当前请求的适配器 HandlerAdapt…...

假设检验学习笔记

1. 假设检验的基本概念 1.1. 原假设&#xff08;零假设&#xff09; 对总体的分布所作的假设用表示&#xff0c;并称为原假设或零假设 在总体分布类型已知的情况下&#xff0c;仅仅涉及总体分布中未知参数的统计假设&#xff0c;称为参数假设 在总体分布类型未知的情况下&#…...

vue3 watch学习

watch的侦听数据源类型 watch的第一个参数为侦听数据源&#xff0c;有4种"数据源"&#xff1a; ref&#xff08;包括计算属性&#xff09; reactive(响应式对象) getter函数 多个数据源组成的数组。 //ref const xref(0)//单个ref watch(x,(newX)>{console.…...

推荐的Pytest插件

推荐的Pytest插件 Pytest的插件生态系统非常丰富&#xff0c;以下是一些特别推荐的Pytest插件&#xff1a; pytest-sugar 这个插件改进了Pytest的默认输出&#xff0c;添加了进度条&#xff0c;并立即显示失败的测试。它不需要额外配置&#xff0c;只需安装即可享受更漂亮、更…...

C语言 | Leetcode C语言题解之第124题二叉树中的最大路径和

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ int max; int dfs(struct TreeNode* root){if(!root) return 0;int left dfs(root->left…...

Linux综合实践(Ubuntu)

目录 一、配置任务 1.1 配置该服务器的软件源为中科大软件源 1.2 安装相关软件openssh-server和vim 1.3 设置双网卡&#xff0c;网卡1为NAT模式&#xff0c;网卡2为桥接模式(桥接模式下&#xff0c;使用静态ip&#xff0c;该网卡数据跟实验室主机网络设置相似&#xff0c;除…...

C++面试题其二

19. STL中unordered_map和map的区别 unordered_map 和 map 都是C标准库中的关联容器&#xff0c;但它们在实现和性能方面有显著区别&#xff1a; 底层实现&#xff1a;map 是基于红黑树实现的有序关联容器&#xff0c;而 unordered_map 是基于哈希表实现的无序关联容器。元素…...

系统架构设计师【第9章】: 软件可靠性基础知识 (核心总结)

文章目录 9.1 软件可靠性基本概念9.1.1 软件可靠性定义9.1.2 软件可靠性的定量描述9.1.3 可靠性目标9.1.4 可靠性测试的意义9.1.5 广义的可靠性测试与狭义的可靠性测试 9.2 软件可靠性建模9.2.1 影响软件可靠性的因素9.2.2 软件可靠性的建模方法9.2.3 软件的可靠性模…...

x264 参考帧管理原理:i_poc_type 变量

x264 参考帧管理 x264 是一个开源的 H.264 视频编码软件,它提供了许多高级特性,包括对参考帧的高效管理。参考帧管理是视频编码中的一个重要部分,它涉及到如何存储、更新和使用已经编码的帧以提高编码效率。 x264 参考帧管理的一些关键点总结如下: 参考帧的初始化和重排序:…...

高级Web Lab2

高级Web Lab2 12 1 按照“Lab 2 基础学习文档”文档完成实验步骤 实验截图&#xff1a; 2 添加了Web3D场景选择按钮&#xff0c;可以选择目标课程或者学习房间。...

Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录 Tcp协议Tcp协议常见API接口1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. int listen(int socket, int backlog);4. int accept(int socket, struct socka…...

实时数据传输:Django 与 MQTT 的完美结合

文章目录 准备工作创建 Django 项目与应用设置 MQTT 服务器编写 Django 视图编写前端模板发布 MQTT 消息运行 Django 项目 在当今互联网应用中&#xff0c;实时数据传输已经成为许多项目的核心需求。无论是社交媒体平台、在线游戏、金融交易还是物联网设备&#xff0c;都需要及…...

创建Django项目及应用

1 创建Project 1个Project可以对应多个app django-admin startproject myproject 2 创建App python manage.py startapp app01 INSTALLED_APPS [# ...app01,app02,# ... ] 如果要让这个应用在项目中起作用&#xff0c;需要在项目的 settings.py 文件的 INSTALLED_APPS 配置…...

Flutter课程分享 -(系统课程 基础 -> 进阶 -> 实战 仿京东商城)

前言 在移动应用开发的世界中&#xff0c;Flutter 作为一款由 Google 推出的开源 UI 软件开发工具包&#xff0c;正迅速赢得开发者们的青睐。其跨平台、高性能、丰富的组件库以及易于学习的特性&#xff0c;使得 Flutter 成为许多开发者的不二选择。然而&#xff0c;对于初学者…...

IDEA 中导入脚手架后该如何处理?

MySQL数据库创建啥的&#xff0c;没啥要说的&#xff01;自行配置即可&#xff01; 1.pom.xml文件&#xff0c;右键&#xff0c;add Maven Project …………&#xff08;将其添加为Maven&#xff09;【下述截图没有add Maven Project 是因为目前已经是Maven了&#xff01;&…...

thinkphp6 queue队列的maxTries自定义

前景需求&#xff1a;在我们用队列的时候发现maxtries的个数时255次&#xff0c;这个太影响其他队列任务 我目前使用的thinkphp版本是6.1 第一部定义一个新的类 CustomDataBase&#xff08;我用的mysql数据库存放的队列&#xff09; 重写__make 和createPlainPayload方法 …...

【PHP项目实战训练】——laravel框架的实战项目中可以做模板的增删查改功能(2)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…...

Kotlin 对象

文章目录 对象表达式&#xff08;匿名对象&#xff09;对象的声明 对象表达式&#xff08;匿名对象&#xff09; 在 Kotlin 中可以使用object {}声明一个匿名的对象&#xff0c;我们无需声明这个对象的类&#xff1a; fun main() {val any object {fun greet() print("…...

力扣 142题 环形链表Ⅱ 记录

题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内…...

乐观锁 or 悲观锁 你怎么选?

你有没有听过这样一句话&#xff1a;悲观者正确&#xff0c;乐观者成功​。那么今天我来分享下什么是乐观锁​和悲观锁。 乐观锁和悲观锁有什么区别&#xff0c;它们什么场景会用 乐观锁 乐观锁基于这样的假设&#xff1a;多个事务在同一时间对同一数据对象进行操作的可能性很…...

《庆余年算法番外篇》:范闲通过最短路径算法在阻止黑骑截杀林相

剧情背景 在《庆余年 2》22集中&#xff0c;林相跟大宝交代完为人处世的人生哲理之后&#xff0c;就要跟大宝告别了 在《庆余年 2》23集中&#xff0c;林相在告老还乡的路上与婉儿和大宝告别后 范闲也在与婉儿的对话中知道黑骑调动是绝密&#xff0c;并把最近一次告老还乡梅…...

大一C语言课设 服装销售系统 代码实现与项目总结

问题分析 服装信息管理及销售管理系统。方便对库存服装的信息管理和添加新服装数据&#xff0c;同时兼具库存数量管理功能。 功能实现 1、建立服装信息库&#xff0c;包括&#xff1a;服装代码、型号、规格、面料、颜色、单价、数量&#xff1b; 2、建立销售信息库&#xff…...

从新手到专家:深入探索JVM垃圾回收--开端篇

引言&#xff1a; 在Java的世界里&#xff0c;垃圾回收&#xff08;Garbage Collection, GC&#xff09;机制扮演着至关重要的角色&#xff0c;它决定了Java应用的性能、稳定性和扩展性。本系列文章旨在深入探讨JVM中的垃圾回收技术&#xff0c;从基础的概念讲起&#xff0c;直…...

R可视化:另类的柱状图

介绍 方格状态的柱状图 加载R包 knitr::opts_chunk$set(echo TRUE, message FALSE, warning FALSE) library(patternplot) library(png) library(ggplot2) library(gridExtra)rm(list ls()) options(stringsAsFactors F)导入数据 data <- read.csv(system.file(&qu…...

Docker的数据管理(数据卷+数据卷容器)

文章目录 一、Docker的数据管理1、概述2、主要的技术&#xff08;三种数据挂载方式&#xff09;2.1、数据卷&#xff08;Volumes&#xff09;2.2、绑定挂载&#xff08;Bind mounts&#xff09;2.3、tmpfs挂载&#xff08;Tmpfs mounts&#xff09;2.4、之间的关系&#xff08;…...

字符串-至多包含K种字符的子串中最长子串(mid)

一、题目描述 二、解题思路 借鉴以下题目思想&#xff0c;使用双指针&#xff0c;外层循环右侧指针移动&#xff0c;内存循环左侧指针移动 字符串-最长不含重复字符的子字符串(mid)-CSDN博客文章浏览阅读622次&#xff0c;点赞17次&#xff0c;收藏4次。java刷题&#xff1a;…...

Docker从安装开始精通

从虚拟机到容器 1.环境配置的难题 软件开发最大的麻烦事之一&#xff0c;就是环境配置。用户计算机的环境都不相同&#xff0c;你怎么知道自家的软件&#xff0c;能在那些机器跑起来&#xff1f; 用户必须保证两件事&#xff1a;操作系统的设置&#xff0c;各种库和组件的安装…...

MFC:初步理解序列化与反序列化(含代码实现)

序列化与反序列化是MFC将对象数据以二进制数据流的形式进行存储和读取的机制&#xff0c;读、写的效率很高。通过序列化与反序列化&#xff0c;可以将程序中对象在内存中数据保存到文件 (磁盘) 或者从文件 (磁盘) 中读取到内存以恢复对象数据&#xff0c;从而实现程序对数据的持…...

python程序控制结构

文章目录 一、python程序控制结构介绍二、顺序结构2.1、print()函数2.2、end参数2.3、input()函数 三、选择结构3.1选择结构的用途 四、循环结构4.1循环结构的构造4.1.1、循环结构的三个要素4.1.2、循环结构的一个要求4.1.3、循环结构的一个关系 4.2、循环语句4.2.1、while语句…...

【GD32】04 - Timer定时器

GD32中的定时器 GD32E230中有七个定时器&#xff0c;六种类型&#xff0c;其中通用的L4版本有两个&#xff0c;其他类型的各一个。 那我们就以通用L4这个类型来敲代码&#xff0c;其他流程是通用的。 通用L4 虽然每种类型的定时器都有自己的结构框图&#xff0c;但是其实大差…...

Golang | Leetcode Golang题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {buy1, sell1 : -prices[0], 0buy2, sell2 : -prices[0], 0for i : 1; i < len(prices); i {buy1 max(buy1, -prices[i])sell1 max(sell1, buy1prices[i])buy2 max(buy2, sell1-prices[i])sell2 m…...

Leetcode2028. 找出缺失的观测数据

Every day a Leetcode 题目来源&#xff1a;2028. 找出缺失的观测数据 解法1&#xff1a;模拟 统计当前 m 个元素的总和 curSum sum(rolls)&#xff0c;总共 mn 个元素和为 total (m n) * mean。 排除 2 种情况&#xff1a; total - curSum > 6 * n&#xff1a;n 个…...

如何在CentOS中合理划分磁盘空间以优化系统性能

目录 前言 理想的分区方案 为什么需要单独分区 安全性 性能 管理和维护 稳定性和可靠性 升级和兼容性 结论 前言 在进行CentOS系统的安装和配置时&#xff0c;合理划分磁盘空间是确保系统性能、安全性和易于管理的关键步骤。本文将探讨如何根据系统的硬件配置和预期用途…...

算法(十一)贪婪算法

文章目录 算法简介算法概念算法举例 经典问题 -背包问题 算法简介 算法概念 贪婪算法&#xff08;Greedy&#xff09;是一种在每一步都采取当前状态下最好的或者最优的选择&#xff0c;从而希望导致结果也是全局最好或者最优的算法。贪婪算法是当下局部的最优判断&#xff0c…...

Rust之函数式语言特性:迭代器和闭包(一):概述

开发环境 Windows 11Rust 1.78.0 VS Code 1.89.1 项目工程 这次创建了新的工程minigrep. 函数式语言特性:迭代器和闭包 Rust的设计从许多现有语言和技术中获得了灵感&#xff0c;其中一个重要影响是函数式编程。函数式编程通常包括通过在参数中传递函数、从其他函数返回函数、…...

配置资源管理

一 Secret Secret 是用来保存密码、token、密钥等敏感数据的 k8s 资源&#xff0c;这类数据虽然也可以存放在 Pod 或者镜像中&#xff0c;但是放在 Secret 中是为了更方便的控制如何使用数据&#xff0c;并减少暴露的风险。 1 有三种类型&#xff1a; kubernetes.io/service…...

unity2020打包webGL时卡进程问题

我使用的2020.3.0f1c1&#xff0c;打包发布WEB版的时候会一直卡到asm2wasm.exe这个进程里&#xff0c;而且CPU占用率90%以上。 即使是打包一个新建项目的空场景也是同样的问题&#xff0c;我尝试过一直卡在这里会如何&#xff0c;结果还真打包成功了。只是打包一个空场景需要20…...

云原生架构相关技术_3.无服务器技术

1.技术特点 1.1面向特定领域的后端云服务&#xff08;BaaS&#xff09; 随着以Kubernetes为代表的云原生技术成为云计算的容器界面&#xff0c;Kubernetes成为云计算的新一代操作系统。面向特定领域的后端云服务&#xff08;BaaS&#xff09;则是这个操作系统上的服务API&…...

Leetcode:Z 字形变换

题目链接&#xff1a;6. Z 字形变换 - 力扣&#xff08;LeetCode&#xff09; 普通版本&#xff08;二维矩阵的直接读写&#xff09; 解决办法&#xff1a;直接依据题目要求新建并填写一个二维数组&#xff0c;最后再将该二维数组中的有效字符按从左到右、从上到下的顺序读取并…...

Python 3 判断文件是否存在

1 使用os.path模块 import osfile_path hello.txtif os.path.exists(file_path):print(f"文件 {file_path} 存在。") else:print(f"文件 {file_path} 不存在。") 2 使用pathlib模块 from pathlib import Pathfile_path Path(word.txt)if file_path.ex…...

(深度学习记录)第TR3周:Transformer 算法详解

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 文本的输入处理中&#xff0c;transformer会将输入文本序列的每个词转化为一个词向量&#xff0c;我们通常会选择一个合适的长度作为输入…...

谷神前端组件增强:自定义列

初始化 $gp.customColumn {}initColumnPool /*** initColumnPool* 初始化列池* * param prefix 前缀* param length 长度* * return Array 列ID数组* */ function initColumnPool (prefix, length) {return Array.from({length}, (value, index) > prefix index) } self…...

31-ESP32-S3-WIFI篇-02 Event Group (事件标记组)

ESP32-S3-WIFI 事件标记组 介绍 在ESP32-S3的WiFi驱动程序中&#xff0c;事件标记组&#xff08;Event Group&#xff09;是一个非常重要的概念。它是FreeRTOS中的一种同步机制&#xff0c;用于在任务之间传递和同步事件。在WiFi驱动程序中&#xff0c;我们使用事件标记组来通…...

构建企业级AI私有知识库

一、引言 在当今竞争激烈的市场环境中&#xff0c;企业为了保持竞争优势&#xff0c;需要高效地管理和利用内部知识资源。构建一个企业级AI私有知识库&#xff0c;不仅可以集中存储和管理企业知识&#xff0c;还能通过人工智能技术实现知识的智能化处理和利用。本文将详细介绍…...

C语言王国——杨氏矩阵

目录 1. 引言 2. 了解杨氏矩阵 3. 思路分析 4. 代码 5. 总结 1. 引言 最近在做二维数组的训练的时候发现了一个很有意思的题&#xff1a; 一看这不是杨氏矩阵嘛&#xff0c;接下来就由姜糖我带大家了解一下这个著名的矩阵。 2. 了解杨氏矩阵 通过查阅百度得知&#xff1a; …...

陪玩小程序都需要怎么做?

开发陪玩小程序需要进行全面的需求分析、功能规划、技术选型、界面设计等一系列步骤。陪玩小程序作为一种新兴的网络服务平台&#xff0c;为用户提供了寻找游戏伙伴、预约陪玩服务等功能&#xff0c;满足了用户在游戏领域的社交互动和技能提升需求。具体分析如下&#xff1a; 需…...

postgressql——子事务可见性判断 性能问题(8)

子事务可见性判断 & 性能 测试SQL BEGIN; PREPARE sel(integer) ASSELECT count(*)FROM contendWHERE id BETWEEN $1 AND $1 + 100; PREPARE upd(integer) ASUPDATE contend SET val = val + 1WHERE id IN ($1, $1 + 10, $1 + 20, $1 + 30);SAVEPOINT a; \set rnd random…...