lambda 表达式
关于C++Lambda表达式的学习记录
在刷到 LeetCode189:轮转数组的地方,使用 reverse 解决这个问题很方便, 然后看题解使用了Lambda表达式,由于我对C++不是很熟,使用AI学习一下。
下面是题解。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int size = nums.size();
auto reverse = [&] (int i, int j) {
while(i < j) {
swap(nums[i++], nums[j--]);
}
};
k %= size;
reverse(0, size-1);
reverse(0, k-1);
reverse(k, size-1);
}
};
一、整体语法拆解
先看完整结构:
auto reverse = [&](int i, int j){
while(i < j){
swap(nums[i++], nums[j--]);
}
};
我们把它拆成 5 个核心部分:
1. auto reverse:变量声明
auto:C++11 引入的自动类型推导,编译器会根据右侧 lambda 表达式的类型,自动推导reverse的类型(本质是 lambda 的闭包类型)。reverse:给这个匿名函数起的 “名字”,后续可以像调用普通函数一样用reverse(i, j)调用。
2. [&]:lambda 捕获子句(捕获列表)
这是 lambda 最关键的部分之一,决定了 lambda 内部能访问哪些外部变量,以及访问方式:
-
[&]:表示以引用方式捕获所有外部可见的变量(即 lambda 定义所在作用域的变量)。 -
这里能直接用
nums和swap(swap是全局 / 命名空间函数),就是因为[&]捕获了外部的nums变量(比如外层函数的 vector / 数组)。 -
补充捕获方式(常用):
写法 含义 []不捕获任何外部变量(空捕获) [=]以值拷贝方式捕获所有外部变量 [&x]只以引用捕获变量 x [x]只以值拷贝捕获变量 x [&,x]引用捕获所有变量,唯独 x 按值捕获
3. (int i, int j):lambda 参数列表
和普通函数的参数列表完全一致:
- 声明了两个整型参数
i和j,表示要反转的区间的起始索引和结束索引(闭区间[i, j])。 - 比如调用
reverse(0, 4),就是反转数组索引 0 到 4 的元素。
4. { ... }:lambda 函数体
核心逻辑是反转区间 [i, j] 的元素:
while(i < j){
swap(nums[i++], nums[j--]);
}
- 循环条件
i < j:保证只交换到区间中间(避免重复交换)。 swap(nums[i++], nums[j--]):swap:交换两个元素(C++ 标准库函数,需包含<algorithm>,或自定义)。i++/j--:交换后,起始索引右移、结束索引左移,直到相遇。
5. 分号 ;:语句结束
lambda 表达式是一个 “表达式”,但赋值给变量时,整体是一条语句,必须以分号结尾。
二、核心特性:lambda 表达式的本质
lambda 是 C++11 引入的匿名函数,本质是:
- 编译器会把 lambda 翻译成一个匿名类(闭包类),并创建该类的一个临时对象(闭包对象)。
auto reverse实际是把这个闭包对象赋值给变量reverse。- 调用
reverse(i, j)等价于调用闭包类的operator()成员函数。
三、使用示例
结合完整场景,比如反转数组的某段区间:
#include <iostream>
#include <vector>
#include <algorithm> // swap 需包含此头文件
using namespace std;
int main() {
vector<int> nums = {1,2,3,4,5};
// 定义 lambda 函数
auto reverse = [&](int i, int j){
while(i < j){
swap(nums[i++], nums[j--]);
}
};
// 调用:反转索引 1 到 3 的元素(2,3,4 → 4,3,2)
reverse(1, 3);
// 输出结果:1 4 3 2 5
for(int num : nums) {
cout << num << " ";
}
return 0;
}
四、关键注意事项
-
捕获的生命周期:
- 因为用
[&]引用捕获nums,所以reverse的生命周期不能超过nums(比如nums销毁后调用reverse会导致野引用)。 - 如果想避免这个问题,可以用
[=]值捕获,但swap会修改拷贝后的nums,原数组不会变(按需选择)。
- 因为用
-
lambda 的可调用性:
- 无捕获的 lambda(
[])可以隐式转换为函数指针,有捕获的不行。 - 本例有捕获,只能通过变量
reverse调用。
- 无捕获的 lambda(
-
参数和返回值:
-
本例 lambda 无返回值(默认
void),如果需要返回值,可显式指定:auto add = [](int a, int b) -> int { return a + b; };
-
五、为什么用这种写法?
- 简洁:无需单独定义一个全局 / 成员函数,就地定义就地使用。
- 闭包特性:自动捕获外部变量,无需手动传参(比如本例不用把
nums作为参数传入reverse)。 - 灵活:常用于算法场景(比如排序的自定义比较、局部的小功能函数)。

浙公网安备 33010602011771号