C++ Lambda 表达式:给 “计算机菜鸡” 的大白话详解
咱先抛开 “表达式”“匿名函数” 这些吓人的词,用个生活例子开头:你在家做饭,突然发现酱油瓶拧不开 —— 你不用专门去楼下找个 “专业拧瓶盖的人”(写个独立函数),而是直接喊旁边看电视的室友:“帮我拧下酱油瓶!”(临时找个 “临时工” 干活)。
Lambda 表达式,就是 C++ 里的 “代码临时工”——不用提前写一个独立函数,需要用的时候,当场写一段小代码块,用完就扔。比如排序、遍历数组时,临时需要一段 “比较逻辑” 或 “处理逻辑”,用 Lambda 比单独写函数方便 10 倍。
一、Lambda 长啥样?—— 拆解 “临时工的工作证”
Lambda 的基本格式很固定,就像给临时工发的工作证,分 4 个部分:
cpp
运行
[捕获规则] (参数列表) -> 返回值类型 { 具体干活的代码 };
咱逐个拆解,用 “拧酱油瓶” 的例子对应:
| 部分 | 大白话解释 | 对应 “拧酱油瓶” 的例子 | 可省略情况 |
|---|---|---|---|
[捕获规则] | 要不要 “带外面的东西” 进来干活(比如外面的变量) | 要不要让室友带 “开瓶器”(外面的工具) | 可以空着(不带任何东西) |
(参数列表) | 干活需要的 “原材料”(比如要拧的瓶子) | 给室友 “酱油瓶”(需要处理的对象) | 没参数时可以空着,甚至省掉 () |
-> 返回值类型 | 干完活要不要 “交成果”(比如拧开后要不要递回来) | 拧开后要不要把瓶子递给你 | 能自动推导出返回值时可省掉 |
{ 代码 } | 具体怎么干活(拧瓶盖的步骤) | 室友拧瓶盖的动作(左手扶瓶、右手拧) | 必须有,不然临时工不知道干啥 |
二、从最简单的开始:不用带东西、不用参数的 Lambda
先写一个 “啥都不带、啥参数没有,就干一件小事” 的 Lambda,比如 “打印一句话”:
cpp
运行
#include <iostream>
using namespace std;
int main() {
// 这就是一个Lambda:啥都不带、没参数、没返回值,就打印一句话
auto print_hello = []() {
cout << "我是Lambda,我在干活!" << endl;
};
// 调用Lambda(跟调用函数一样,加个())
print_hello();
return 0;
}
运行结果:我是Lambda,我在干活!
关键理解:
auto print_hello:用auto自动推导 Lambda 的类型(不用管它具体叫啥,反正能存起来);[]:空的,意思是 “不捕获外面任何变量”(临时工不带任何工具);():空的,意思是 “不需要参数”(临时工不用原材料,直接干活);- 没写
-> 返回值类型:因为代码里没有return,C++ 能自动推导出 “返回值是 void”(干完活不用交成果)。
三、进阶 1:需要 “原材料”(参数)的 Lambda
比如要一个 “计算两个数相加” 的 Lambda,需要传入两个数(参数):
cpp
运行
int main() {
// Lambda:需要两个int参数,返回它们的和
auto add = [](int a, int b) -> int {
return a + b; // 有return,返回值是int
};
// 调用Lambda,传两个参数
int result = add(3, 5);
cout << "3+5=" << result << endl; // 输出:3+5=8
return 0;
}
小优化:返回值类型能省!因为 C++ 能从return a + b里看出 “返回值是 int”,所以-> int可以删掉,简化成:
cpp
运行
auto add = [](int a, int b) { return a + b; }; // 一样能用
四、进阶 2:需要 “带外面的东西”(捕获外部变量)
这是 Lambda 最核心的功能 —— 能 “拿外面的变量” 进来用。比如外面有个变量x=10,想让 Lambda 用它来计算:
情况 1:值捕获(拿副本,改了不影响外面)
用[x]表示 “值捕获 x”—— 相当于给临时工 “复印一份 x 的资料”,临时工改自己的副本,不影响你手里的原件:
cpp
运行
int main() {
int x = 10; // 外面的变量
// Lambda:值捕获x(拿x的副本),参数是y
auto calculate = [x](int y) {
// x = 20; // 编译错误!值捕获的副本不能改(默认是const的)
return x + y; // 用副本x和参数y计算
};
int result = calculate(5);
cout << "10+5=" << result << endl; // 输出:10+5=5
cout << "外面的x还是:" << x << endl; // 输出:外面的x还是:10(没被改)
return 0;
}
想改值捕获的副本? 加个mutable(意思是 “允许改副本”):
cpp
运行
auto calculate = [x](int y) mutable {
x = 20; // 现在能改副本了
return x + y;
};
int result = calculate(5); // 20+5=25
cout << "外面的x还是:" << x << endl; // 还是10(改的是副本)
情况 2:引用捕获(拿地址,改了影响外面)
用[&x]表示 “引用捕获 x”—— 相当于给临时工 “x 的地址”,临时工改的就是你手里的原件(跟左值引用int&一个意思):
cpp
运行
int main() {
int x = 10;
// Lambda:引用捕获x(拿x的地址)
auto add_to_x = [&x](int y) {
x += y; // 改的是外面的x(因为是引用)
};
add_to_x(5);
cout << "外面的x变成了:" << x << endl; // 输出:外面的x变成了:15
return 0;
}
注意:引用捕获要小心!如果外面的变量先 “消失”(比如函数结束),Lambda 再用引用就会出错(相当于拿了个无效地址)。
情况 3:批量捕获(不用一个个写变量)
如果外面变量多,不想一个个写,用批量捕获规则:
[=]:值捕获 “所有用到的外部变量”(省心,不用列变量名);[&]:引用捕获 “所有用到的外部变量”(更省心,但要注意变量生命周期);
例子([=]批量值捕获):
cpp
运行
int main() {
int a = 2, b = 3;
// Lambda:值捕获所有用到的变量(a和b)
auto multiply = [=]() {
return a * b; // 直接用外面的a和b,不用一个个写[ a, b ]
};
cout << "2*3=" << multiply() << endl; // 输出:2*3=6
return 0;
}
五、Lambda 最常用的场景:配合 STL 算法
Lambda 最大的用处,是在sort(排序)、for_each(遍历)这些 STL 算法里,临时写 “处理逻辑”。比如给数组排序,不用单独写一个比较函数:
例子 1:给数组按 “从大到小” 排序
cpp
运行
#include <iostream>
#include <vector>
#include <algorithm> // 包含sort
using namespace std;
int main() {
vector<int> nums = {3, 1, 4, 1, 5};
// 用sort排序,第三个参数直接写Lambda(比较逻辑)
sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 比较规则:a比b大就排在前面(从大到小)
});
// 遍历数组,打印结果
for (int num : nums) {
cout << num << " "; // 输出:5 4 3 1 1
}
return 0;
}
如果不用 Lambda,你得单独写一个比较函数:
cpp
运行
// 单独写的比较函数
bool compare(int a, int b) {
return a > b;
}
// 然后sort里传函数名:sort(nums.begin(), nums.end(), compare);
对比下来,Lambda 不用 “额外写函数”,逻辑直接嵌在sort里,代码更紧凑。
例子 2:遍历数组,给每个元素加 10
用for_each遍历,Lambda 负责 “给元素加 10”:
cpp
运行
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
// for_each:遍历每个元素,用Lambda处理
for_each(nums.begin(), nums.end(), [](int& num) {
num += 10; // 引用捕获元素,直接修改原数组
});
for (int num : nums) {
cout << num << " "; // 输出:11 12 13
}
return 0;
}
六、总结:Lambda 的核心优点(为啥要用它?)
- 简洁:不用单独写函数,逻辑当场写、当场用,代码少;
- 灵活:能捕获外部变量,配合 STL 算法超方便;
- 临时:用完就扔,不用给函数起名字(很多时候函数只用一次,起名字反而麻烦)。
七、给 “菜鸡” 的避坑指南
- 值捕获默认不能改:要改副本必须加
mutable; - 引用捕获要注意生命周期:外面的变量没了,Lambda 就别用引用了;
- 别滥用捕获:能不捕获就不捕获,能值捕获就别引用捕获(减少 bug);
- 返回值能省就省:C++ 能自动推导返回值,不用硬写
-> 类型。
如果现在让你写一个 “给数组里的偶数加 5” 的逻辑,你应该能想到:用for_each遍历,配合一个 “判断是否是偶数、是就加 5” 的 Lambda—— 这就是 Lambda 的魅力,简单场景下,比写独立函数快多了!
更多推荐



所有评论(0)