【C++进阶篇】C++11新特性(下篇)
C++函数式编程黑魔法:Lambda与包装器实战全解析
- 一. lambda表达式
- 1.1 仿函数使用
- 1.2 lambda表达式的语法
- 1.3 lambda表达式使用
- 1.3.1 传值和传引用捕捉
- 1.3.2 隐式捕捉
- 1.3.3 混合捕捉
- 1.4 lambda表达式原理
- 1.5 lambda优点及建议
- 二. 包装器
- 2.1 function
- 2.2 bind绑定
- 三. 最后
一. lambda表达式
lambda可以像仿函数一样传给函数,像sort,它的优势在于代码清晰度高,且简便,它的本质是一个匿名对象。它没有类型,可以使用auto接收推导类型。
1.1 仿函数使用
仿函数作为对象,控制sort排升序还是降序。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;struct cmpGreater
{bool operator()(int X, int Y){return X > Y;}
};struct cmpLess
{bool operator()(int X, int Y){return X < Y;}
};
int main()
{vector<int> arr{ 10,4,2,6,7,3,8,0,1,5,9 };//仿函数传递对象sort(arr.begin(), arr.end(), cmpLess());//降序for (auto e : arr)cout << e << " ";cout << endl;sort(arr.begin(), arr.end(), cmpGreater());//降序for (auto e : arr)cout << e << " ";return 0;
}
创建vector对象,通过sort排序,仿函数控制升序行为。
- 输出结果:
上面已经说过lambda也可以完成仿函数的行为,下面展示一下。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;int main()
{vector<int> arr{ 10,4,2,6,7,3,8,0,1,5,9 };//lambda表达式//升序sort(arr.begin(), arr.end(), [](int x, int y)-> int {return x > y; });//升序for (auto e : arr)cout << e << " ";cout << endl;//降序sort(arr.begin(), arr.end(), [](int x, int y)-> int {return x < y; });//降序for (auto e : arr)cout << e << " ";cout << endl;return 0;
}
输出结果:
sort函数使用lambda代替仿函数,从结果可以看出一样完成一样的功能。
1.2 lambda表达式的语法
C/C++ lambda 语法格式:
[capture-list] (parameters)-> return type { function boby };
解释:
- [Capture List] :捕捉列表,用于定义Lambda如何访问外部作用域的变量。
- (Parameters): 参数列表定义 Lambda的输入参数。
- ->return type :返回值类型,⽤追踪返回类型形式声明函数的返回值类型,没有返回值时此
部分可省略。⼀般返回值类型明确情况下,也可省略,由编译器对返回类型进⾏推导。 - {function boby} :函数体,函数体内的实现跟普通函数完全类似,在该函数体内,除了可以
使⽤其参数外,还可以使⽤所有捕获到的变量,函数体为空也不能省略。
其中,参数列表,mutable,-> returntype可以省略。
- 省略参数列表,表示当前是一个无参的参数对象。
- 省略mutable,表示捕捉的对象保持其常性。
- 省略->returntype,返回值类型由编译器自动推导。
注意:捕捉列表和函数体不可省略,很容易理解。也就是说最基本的 lambda 表达式 只需要写 [ ]{ }
int main()
{//最简单的lambda表达式[] {};return 0;
}
此时表达式相当于返回值为空,参数为空,函数体为空的匿名对象。
void func() { };
lambda表达式本质是匿名对象,而func是一个有名对象,直接调用即可。
1.3 lambda表达式使用
上面说过lambda是匿名对象,该对象出了作用域(当前行)就销毁了,其它作用域无法使用它。
lambda只允许使用函数体及参数中的变量,要想使用外层变量,此时就需要捕捉。
捕捉分为,值捕捉,引用捕捉,隐式捕捉,全捕捉,即混合捕捉等。
1.3.1 传值和传引用捕捉
下面通过写代码,看看编译器现象。
在lambda表达式外定义几个变量,看看lambda表达式是否能使用???
需要捕捉,先进行值捕捉,看看现象。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;int main()
{int x = 10, y = 20;[x](int a, int b)//当前作用域调用该匿名对象{a++;b++;x;cout << "x = " << x << endl;}(10,20);auto ret1 = [x](int a, int b)//使用对象构建lambda表达式{a++;b++;x;cout << "x = " << x << endl;};ret1(20, 30);return 0;
}
输出结果:
下面我们对捕捉的对象进行修改,看看行不行???
从上图可以看出编译器报错,不支持,我们就需要修改呢,有没有办法???
有的兄弟,有的,可以是用mutable关键字,加在参数列表即可。默认捕捉的值具有常性。
- 功能:捕捉的值可以去除该值的常性。
int main()
{int x = 10, y = 20;[x](int a, int b)//当前作用域调用该匿名对象mutable {a++;b++;x++;cout << "x = " << x << endl;}(10, 20);return 0;
}
从结果可以看出该值进行了自增。且不是该对象的拷贝对象。
还有其它的方法也可以完成该功能:传引用捕捉。
#include<iostream>
#include<algorithm>
using namespace std;int main()
{int x = 10, y = 20;//传引用捕捉[&x](int a, int b)//当前作用域调用该匿名对象{a++;b++;x++;cout << "x = " << x << endl;}(10, 20);return 0;
}
一样的输出结果。
1.3.2 隐式捕捉
在捕捉列表显示写个 = ,表示为隐式捕捉,我们用了哪些变量就捕捉哪些变量,该行为编译器会自动推导。
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;int main()
{int x = 10, y = 20,a=30,b=40,z=50;//隐式引用捕捉[=](){int ret = x + y + a;cout << "ret = " << ret << endl;}();//等价于auto ret = [=](){ int ret = x + y + a; cout << "ret = " << ret << endl;};ret();return 0;
}
输出结果:
隐式捕捉好处在于代码简洁,提升代码表达力的利器。
1.3.3 混合捕捉
显示捕捉分为传值捕捉和传引用捕捉。混合捕捉是隐式捕捉和显示捕捉的混合体。
规则:
- 当使用混合捕捉时,第一个元素必须是&或=。
- &混合捕捉时,后面的捕捉变量必须是值捕捉。
- =混合捕捉时,后面的捕捉变量必须是引用捕捉。
#include<iostream>
#include<algorithm>
using namespace std;int main()
{int a = 10, b = 20, c = 30, d = 90, x = 1, y = 2, z = 3;//混合捕捉,第1个为隐式捕捉auto ret = [=,&a,&b](){a++;b++;int ret = a + b + x + y;cout << "ret= " << ret << endl;return ret;};ret();cout << "之前: x = " << x << ", y = " << y << endl;//混合捕捉,第1个为隐式捕捉auto ret1 = [&, a, b]() {x++;y++;int ret = a + b + x + y;cout << "之后: ";cout << "x = " << x <<", y = " << y << endl;return ret;};ret1();return 0;
}
输出结果:
从结果可以看出x和y都进行自增,符合预期行为。
注意:局部静态变量和全局变量不需要捕捉,强行捕捉会报错。
- 报错示例:
默认情况下, lambda 捕捉列表是被const修饰的,也就是说传值捕捉的过来的对象不能修改,mutable加在参数列表的后⾯可以取消其常量性,也就说使⽤该修饰符后,传值捕捉的对象就可以修改了,但是修改还是形参对象,不会影响实参。
#include<iostream>
#include<algorithm>
using namespace std;int main()
{int x = 10;[x]() mutable{x++;cout << "lambda表达式里的x = " << x << endl;return x; }();cout << "lambda表达式外的x = " << x << endl;
}
从结果可以看出x并没有改变,捕捉的对象确实是存储在lambda表达式中临时对象。
当lambda表达式定义在全局变量捕捉列表必须为空,因为没有其它的变量可以被捉到。
1.4 lambda表达式原理
lambda对象的大小。
#include<iostream>
#include<algorithm>
using namespace std;//普通函数
int add(int x, int y)
{return x + y;
}//仿函数
struct ADD
{int operator()(int x, int y){return x + y;};
};int main()
{auto typec = add;ADD add1;auto ret = [](int x, int y) {return x + y; };cout << "普通函数: " << sizeof(typec) << endl;cout << "仿函数: " << sizeof(add1) << endl;cout << "lambda表达式: " << sizeof(ret) << endl;return 0;
}
可以看出lambda表达式对象与仿函数一样都是大小都是1字节。空类(没有成员变量)独占1个字节。
VS2022两者汇编代码:
可以看出汇编代码完全一致,所以编译器就是把lambda表达式当做仿函数。
结论:lambda 表达式 本质上就是一个 仿函数。
1.5 lambda优点及建议
- 代码简洁性革命
- 减少模板代码:替代单方法接口的匿名类(如Java的Runnable),代码量减少50%-70%
- 内联逻辑封装:在算法中间件(如std::sort的比较函数)中直接嵌入逻辑,避免上下文切换
- 函数式编程加速器
- 高阶函数支持:天然适配map/filter/reduce等操作,实现链式数据处理流水线
- 不可变数据:强制以表达式形式返回值,天然支持无副作用编程
- 延迟执行专家
- 回调封装:在GUI事件处理、异步编程中封装待执行逻辑
- 策略模式实现:动态替换算法逻辑(如Java的Comparator接口)
- 并发编程利器
- 无状态共享:天然适配并行流(如Java的parallelStream())
- 线程安全默认:值捕获([=])创建的副本天然隔离线程间数据
最佳实践:Lambda表达式是现代编程的瑞士军刀,但需遵循"3行法则":超过3行的逻辑应重构为具名函数。合理使用可显著提升代码表现力,但需在简洁性与可维护性间找到平衡点。建议从简单场景开始实践,逐步掌握其高级特性,并始终关注变量作用域和线程安全性。
二. 包装器
包装器分为函数包装器和类包装器。
2.1 function
一个结构一致的函数,lambda表达式基本相同。
// 普通函数
void func(int n)
{cout << "void func(int n): " << n << endl;
}// 仿函数
struct Func
{
public:void operator()(int n){cout << "void operator()(int n): " << n << endl;}
};// lambda 表达式
auto lambda = [](int n)->void{cout << "[](int n)->void: " << n << endl;};int main()
{void(*pf)(int);//函数指针pf = func;//函数名本身就是函数的地址pf(10);//Func f;//类实例化出对象//pf = f;//errorpf = lambda;pf(20);return 0;
}
输出结果:
可以看出函数指针无法指向类对象,仿函数对象。
有没有什么东西可以完成该功能。包装器就是解药。
function就是一个类模版,可以包装任何对象,包括函数指针、仿函数、lambda、宾得表达式等。
function是基于 可变模版参数 实现的,原型如下:
template <class Ret, class… Args>
class function<Ret(Args…)>;
其中Ret是返回值类型,Args为模版参数包,表示传给函数的参数,function 模板类通过 模板特化 指明了包装的函数对象类型。
注意:使用function前,需要包含头文件
int main()
{// 包装器function<void(int)> f;f = func;f(10);f = Func();f(20);f = lambda;f(30);return 0;
}
function还可以包装 类内成员函数。
包装静态成员函数相对较简单,只需指明类域即可。
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;class Plus
{
public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}
private:int _n;
};int main()
{function<int(int,int)> f = Plus::plusi;//function<int(int,int)> f = &Plus::plusi;//correctcout << "f(10, 20) = " << f(10, 20) << endl;return 0;
}
下面进行包装静态成员函数,相对复杂一点。使用上述方法会报错。
解决办法:在包装时,指定第一个参数为类,并且需要取地址。
function<double(Plus,double, double)> f = &Plus::plusd;//因为成员函数还多了个this指针,这个&不可省略//匿名对象
f(Plus(), 10, 20);//普通对象
Plus p;
f(p, 10, 20);
return 0;
- 细节:为什么包装静态成员函数不需要取地址,而非静态成员函数需要取地址???
非静态成员函数必须通过&Plus::plusd、显式获取成员函数指针,并通过std::bind、Lambda或std::mem_fn绑定对象实例,否则无法直接调用。
- 本质区别:
当第一参数设置为类的指针时,看看现象。
第一个参数设置为指针,普通函数可以,对于匿名对象就不可以。
再将第一参数设置为引用版本看看,能不能解决问题。
可能有人会想第一个参数用const修饰,但是会导致普通的对象无法使用,因为涉及权限放大,从非const到const的放大。
最佳实践:将第一个参数设置为普通的类即可。
2.2 bind绑定
bind 是⼀个函数模板,它也是⼀个可调⽤对象的包装器,可以把他看做⼀个函数适配器,对接收
的fn可调⽤对象进⾏处理后返回⼀个可调⽤对象。 bind 可以⽤来调整参数个数和参数顺序。
bind 也在这个头⽂件中。
原型:
template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
fn 是传递的 函数对象,args 是传给函数的 可变参数包,这里使用了 万能引用(引用折叠),使其在进行模板类型推导时,既能引用左值,也能引用右值。
使用bind改变参数顺序。
void func(int x, int y)
{cout << "void func(int x, int y)" << x << " " << y << endl;
}int main()
{//正常调用func(10, 20);auto ret = bind(func, -2,-1);ret(10, 20);return 0;
}
输出结果好像不对,因为没有指定类域,导致-2,-1传递给函数。现在指定一下。
placeholders::_2, placeholders::_1
结果好像是对的。
bind的底层是仿函数,通过bind绑定的函数将参数根据用户指定的行为传递给函数,函数做出行为。
bind主要作用用于指定参数的个数。
下面我们将第一个参数指定。
int main()
{auto f = bind(func, 100, placeholders::_1);f(10);f(10, 20);return 0;
}
此时如果坚持传递参数,会优先使用绑定的参数,再从函数参数列表中,从左到右选择参数进行传递,直到参数数量符合,比如这里第二次调用虽然传递了 10 和 20,但实际调用 Func 时,RFunc 会先传递之前绑定的值 100 作为参数1传递,而 10 会作为参数2传递,至于 20 会被丢弃。
这里的不能这样写 auto f = bind(func, 100, placeholders::_2);因为参数的个数不满足。
看到上面没都要传递类对象,而bind的引入将一个参数类绑死就不需要传入。
class MyClass {
public:void memberFunc(int a, int b) {cout << "a = " << a << ", b = " << b << endl;}
};int main() {MyClass obj;// 绑定类成员函数,固定第一个参数为100auto bound_func = bind(&MyClass::memberFunc, &obj, 100, _1);// 调用绑定后的函数:只需传递第二个参数(原函数的第二个参数)bound_func(200); // 输出:a = 100, b = 200return 0;
}
输出结果:
就不需要手动每次都传递对象。下面看需要传递的麻烦处。
class MyClass {
public:void memberFunc(int a, int b) {cout << "a = " << a << ", b = " << b<< ", this = " << this << endl;}
};int main() {MyClass obj1, obj2;// 绑定成员函数,但保留对象实例的位置为占位符auto bound_func = bind(&MyClass::memberFunc, _1, 100, _2);// 调用时需显式传递对象实例和其他参数bound_func(obj1, 200); // 输出:a = 100, b = 200, this = 0x7ffd...(obj1的地址)bound_func(obj2, 300); // 输出:a = 100, b = 300, this = 0x7ffd...(obj2的地址)return 0;
}
三. 最后
本文深入解析了C++中lambda表达式与函数包装器的核心机制及实践应用。lambda作为匿名函数对象,通过值/引用/隐式/混合捕捉实现灵活作用域访问,本质是编译器生成的仿函数,支持代码内联封装与函数式编程范式。std::function作为统一调用包装器,可封装普通函数、仿函数、lambda及成员函数,解决函数指针类型限制问题。std::bind通过参数重排与对象绑定实现接口适配,尤其适用于回调场景。三者协同可显著提升代码简洁性,在算法排序、事件处理等场景中简化模板代码,平衡开发效率与可维护性,是现代C++函数式编程的重要工具链。关于线程的部分后面再补充。,也重要
相关文章:

【C++进阶篇】C++11新特性(下篇)
C函数式编程黑魔法:Lambda与包装器实战全解析 一. lambda表达式1.1 仿函数使用1.2 lambda表达式的语法1.3 lambda表达式使用1.3.1 传值和传引用捕捉1.3.2 隐式捕捉1.3.3 混合捕捉 1.4 lambda表达式原理1.5 lambda优点及建议 二. 包装器2.1 function2.2 bind绑定 三.…...

全生命周期的智慧城市管理
前言 全生命周期的智慧城市管理。未来,城市将在 实现从基础设施建设、日常运营到数据管理的 全生命周期统筹。这将避免过去智慧城市建设 中出现的“碎片化”问题,实现资源的高效配 置和项目的协调发展。城市管理者将运用先进 的信息技术,如物…...

echarts柱状图实现动态展示时报错
echarts柱状图实现动态展示时报错 1、问题: 在使用Echarts柱状图时,当数据量过多,x轴展示不下的时候,可以使用dataZoom实现动态展示。如下图所示: 但是当鼠标放在图上面滚动滚轮时或拖动滚动条时会报错,…...
Redis故障转移
概述 本文主要讲述了Redis故障转移的原理及过程,可与「Redis高可用架构」文章一同阅读,可更好理解相关内容,及整个Redis高可用架构的实现原理。 Leader 选举 哨兵首先进入 WATI_START 状态进行准备,等待哨兵成为哨兵集群的 Leade…...
STM32学习笔记:定时器(TIM)原理与应用(详解篇)
前言 定时器是STM32微控制器中最重要且最常用的外设之一,它不仅能提供精确的定时功能,还能实现PWM输出、输入捕获、编码器接口等多种功能。本文将全面介绍STM32的通用定时器,包括其工作原理、配置方法和典型应用。 一、STM32定时器概述 定…...
JAVA获取ES连接并查询所有数据
我们的项目要获取es连接,新版本和旧版本有不小的区别,在8.17.0版本使用的是 ElasticsearchClient <dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>8.17…...

408第一季 - 数据结构 - 线性表
只能用C/C! 顺序表 闲聊 线性表的逻辑顺序和物理顺序相同 都是1234 顺序表的优点: 随机访问,随机访问的意思是访问的时间 和位置没有关系,访问下标1和100一样的,更深层就是直接计算 a100 * 数组大小,随便…...

第23讲、Odoo18 邮件系统整体架构
目录 Odoo 邮件系统整体架构邮件发送方式邮件模板配置SMTP 邮件服务器配置邮件发送过程开发中常见邮件发送需求常见问题排查提示与最佳实践完整示例:审批通过自动发邮件门户表单自动邮件通知案例邮件队列与异步发送邮件添加附件邮件日志与调试多语言邮件模板邮件安…...
【QT面试题】(三)
文章目录 Qt信号槽的优点及缺点Qt中的文件流和数据流区别?Qt中show和exec区别QT多线程使用的方法 (4种)QString与基本数据类型如何转换?QT保证多线程安全事件与信号的区别connect函数的连接方式?信号与槽的多种用法Qt的事件过滤器有哪些同步和…...
DeepSeek09-open-webui使用
Open WebUI 完全指南:从安装到知识库搭建与异常处理 最后更新:2025年6月7日 | 适用版本:Open WebUI v0.6.x 一、安装部署 1.1 系统要求 **Python 3.12 **(严格版本要求,更高版本3.13不兼容)Node.js 20.x内…...

HarmonyOS:Counter计数器组件
一、概述 计数器组件,提供相应的增加或者减少的计数操作。 说明 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 二、属性 除支持通用属性外,还支持以下属性。 enableInc enableInc(value: b…...
数据类型 -- 字符
在C中,字符型(char)用于存储单个字符,如字母、数字、符号等。字符型是最基本的数据类型之一,常用于处理文本、字符数组(字符串)等场景。 1. 基本类型 • char:标准字符类型&#x…...
WordZero:让Markdown与Word文档自由转换的Golang利器
在日常工作中,我们经常需要在Markdown和Word文档之间进行转换。Markdown方便编写和版本控制,而Word文档更适合正式的商务环境。作为一名Golang开发者,我开发了WordZero这个库,专门解决这个痛点。 项目背景 GitHub仓库࿱…...

sqlsugar WhereIF条件的大于等于和等于查出来的坑
一、如下图所示,当我用 .WhereIF(input.Plancontroltype > 0, u > u.Plancontroltype (DnjqPlancontroltype)input.Plancontroltype) 这里面用等于的时候,返回结果一条数据都没有。 上图中生成的SQL如下: SELECT id AS Id ,code AS …...

Pandas 技术解析:从数据结构到应用场景的深度探索
序 我最早用Python做大数据项目时,接触最早的就是Pandas了。觉得对于IT技术人员而言,它是可以属于多场景的存在,因为它的本身就是数据驱动的技术生态中,对于软件工程师而言,它是快速构建数据处理管道的基石࿱…...

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)
数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握) 前言一、为什么需要规范化1. 我们先想一个…...
[c#]判定当前软件是否用管理员权限打开
有时一些软件的逻辑中需要使用管理员权限对某些文件进行修改时,那么该软件在执行或者打开的场合,就需要用使用管理员身份运行才能达到效果。那么在c#里,如何判定该软件是否是对管理员身份运的呢? 1.取得当前的windows用户。 2.取得…...

并发编程实战(生产者消费者模型)
在并发编程中使用生产者和消费者模式能够解决绝大多数的并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。 生产者和消费者模式: 在线程的世界中生产者就是产生数据的线程,而消费者则是消费数据的线程。在多线程开…...
分布式微服务系统架构第144集:FastAPI全栈开发教育系统
加群联系作者vx:xiaoda0423 仓库地址:https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ https://github.com/webVueBlog/fastapi_plus https://webvueblog.github.io/JavaPlusDoc/ 使用docker搭建常用开发环境 docker安装mysql docker ru…...
el-tabs 切换时数据不更新的问题
最近业务需求,需要在页面中使用tabs,使用过程中出现tabs切换,数据不更新的问题,以下是思路和解决办法。 Vue 会追踪你在模板中绑定的数据,并在数据发生变化时重新渲染相应的部分。但在使用 el-tabs 时,有时…...

git小乌龟不显示图标状态解决方案
第一步 在开始菜单的搜索处,输入regedit命令,打开注册表。 第二步 在注册表编辑器中,找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers 这一项。 第三步 让Tortoise相关的项目排在前…...

获取 OpenAI API Key
你可以按照以下步骤来获取 openai.api_key,用于调用 OpenAI 的 GPT-4、DALLE、Whisper 等 API 服务: 🧭 获取 OpenAI API Key 的步骤: ✅ 1. 注册或登录 OpenAI 账号 打开 https://platform.openai.com/ 使用你的邮箱或 Google/…...

【Android基础回顾】五:AMS(Activity Manager Service)
Android 的 AMS(Activity Manager Service)是 Android 系统中的核心服务之一,负责管理整个应用生命周期、任务栈、进程和四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的运行。它运行在系统进程 s…...

pycharm中提示C++ compiler not found -- please install a compiler
1.最近用pycharm编译一个开源库,编译的依赖c compiler 2.单单使用pycharm编译,编译器报错C compiler not found – please install a compiler 3.需要在配置环境中引入对应库 4.从新编译后没有提示:C compiler not found – please install a compiler错误。...
类型别名与类型自动推导
类型别名与类型的自动推导 类型别名 为什么要引入类型别名? 为了给类型赋予特殊含义或便于使用 典型用途 (1)增强代码可移植性 例如:size_t (在不同系统中可能是unsigned int 或 unsigned long) 首先是…...

一站式直播工具:助力内容创作者高效开启直播新时代
近年来,随着互联网技术的不断进步和短视频、直播行业的爆发式增长,越来越多的企业和个人投入到直播电商、互动娱乐、在线教育等场景。直播运营过程中,涉及到数据统计、弹幕互动、流程自动化、内容同步等诸多环节。如何提升运营效率、减少人工…...
【学习笔记】Lamba表达式[匿名函数]
【学习笔记】Lamba表达式[匿名函数] Lamba表达式格式函数模板Lamba表达式例子 Lamba表达式格式 格式: [捕获列表](参数列表) -> 返回类型 { 函数体 }1、捕获列表:指定如何访问外部变量(如 [&x] 引用捕获,[x] 值捕获&#…...
学习笔记(26):线性代数-张量的降维求和,简单示例
学习笔记(26):线性代数-张量的降维求和,简单示例 1.先理解 “轴(Axis)” 的含义 张量的 “轴” 可以理解为 维度的方向索引 。对于形状为 (2, 3, 4) 的张量,3 个轴的含义是: 轴 0(axis0&…...

以智能管理为基础,楼宇自控打造建筑碳中和新路径
在全球气候变化的严峻形势下,“碳中和”已成为各国发展的重要战略目标。建筑行业作为能源消耗与碳排放的“大户”,其运行阶段的能耗占全社会总能耗近40%,碳排放占比与之相当,实现建筑碳中和迫在眉睫。传统建筑管理模式下ÿ…...
81 实战一:给root目录扩容
添加一块100G硬盘 vgextend centos /dev/sdb1 /dev/sdc lvextend -L +120G /dev/centos/root xfs_growfs /dev/centos/root df -h 看是否扩容成功 82 实战二:给swap空间扩容 添加一块20G硬盘 fdisk -l 可以看到新添加的硬盘 vgextend centos /dev/sdd …...