引言在前面 STL 系列中我们大量使用了这样的写法sort(v.begin(), v.end(), [](int a, int b) { return a b; });这里的[](int a, int b) { return a b; }就是Lambda 表达式。它是 C11 引入的核心特性之一本质是一个匿名的仿函数对象。相比传统仿函数需要单独定义一个类Lambda 可以在使用时直接写出逻辑代码更紧凑、可读性更高。Lambda 在现代 C 中几乎无处不在——STL 算法、回调函数、线程创建、异步编程……掌握 Lambda 是写出优雅 C 代码的必备技能。第一部分Lambda 的基本语法一、完整语法结构五个部分可以省略其中几个最简单的 Lambda 可以写成[]{}。部分作用可否省略[capture]捕获外部变量❌ 不能省(parameters)参数列表✅ 无参可省mutable允许修改按值捕获的变量✅- return_type显式指定返回类型✅ 可自动推导{ body }函数体❌ 不能省二、从简单到复杂#include iostream using namespace std; int main() { // 1. 最简单的 Lambda无参无返回值 [] { cout Hello Lambda endl; }(); // 2. 带参数 [](int a, int b) { cout a b endl; }(3, 5); // 8 // 3. 有返回值自动推导 auto add [](int a, int b) { return a b; }; cout add(3, 5) endl; // 8 // 4. 显式指定返回类型 auto divide [](double a, double b) - double { return a / b; }; cout divide(5.0, 2.0) endl; // 2.5 return 0; }返回类型推导规则如果函数体只有一条return语句编译器会自动推导返回类型。如果有多条return且类型不同必须用-显式指定。第二部分捕获列表捕获列表是 Lambda 最核心、区别于普通函数的关键特性。一、值捕获 vs 引用捕获int a 10, b 20; // 值捕获拷贝一份Lambda 内修改不影响外部 auto f1 [a, b] { return a b; }; // a 100; // 不影响 f1 内部的 a已经拷贝了 // 引用捕获Lambda 内修改会影响外部 auto f2 [a, b] { a 100; // 修改了外部的 a b 200; }; f2(); cout a b endl; // 100 200二、捕获方式总览写法含义示例[x]值捕获 x[x]{ return x; }[x]引用捕获 x[x]{ x 10; }[]值捕获所有外部变量[]{ return a b; }[]引用捕获所有外部变量[]{ a 10; b 20; }[, x]默认值捕获x 引用捕获[, x]{ x; return a; }[, x]默认引用捕获x 值捕获[, x]{ return x; }[this]捕获当前对象的 this 指针[this]{ return this-val; }int a 1, b 2, c 3; // 默认值捕获所有 auto f1 [] { return a b c; }; // 拷贝 a, b, c // 默认引用捕获所有 auto f2 [] { a 10; b 20; }; // 引用 a, b, c // 混合默认值捕获但 c 引用捕获 auto f3 [, c] { // a, b 是拷贝c 是引用 c 100; return a b c; };三、捕获的时机int x 10; // Lambda 定义时捕获不是调用时捕获 auto f [x] { return x; }; x 100; cout f() endl; // 10不是 100定义时 x10 已被拷贝第三部分mutable 关键字按值捕获的变量在 Lambda 内默认是只读的。要修改它们需要mutable。int x 10; // ❌ 错误按值捕获的变量是只读的 // auto f1 [x] { x; return x; }; // ✅ 加 mutable 后可以修改不影响外部变量 auto f2 [x]() mutable { x; return x; }; cout f2() endl; // 11 cout f2() endl; // 12x 是 Lambda 内部的副本会累积 cout x endl; // 10外部 x 不受影响mutable的本质去掉 Lambda 的operator()上的const修饰符。第四部分Lambda 的本质Lambda 本质上是编译器自动生成的匿名仿函数类。auto f [x](int a) { return a x; }; // 编译器大致会生成这样的类 class __Lambda_12345 { int x; // 捕获的变量成为成员变量 public: __Lambda_12345(int val) : x(val) {} int operator()(int a) const { return a x; } };这意味着Lambda 是一个对象有自己的内存空间按值捕获的变量存储在 Lambda 对象内部Lambda 可以像对象一样被复制、传递、存储// Lambda 作为函数参数最常见 sort(v.begin(), v.end(), [](int a, int b) { return a b; }); // Lambda 赋值给变量 auto cmp [](int a, int b) { return a b; }; sort(v.begin(), v.end(), cmp); // Lambda 存储在容器中 vectorfunctionbool(int,int) funcs; funcs.push_back([](int a, int b) { return a b; });第五部分常用场景一、STL 算法最常见#include algorithm #include vector using namespace std; vectorint v {5, 2, 8, 1, 9, 3, 2, 5}; // sort 自定义比较 sort(v.begin(), v.end(), [](int a, int b) { return a b; }); // find_if 条件查找 auto it find_if(v.begin(), v.end(), [](int x) { return x 5; }); // count_if 条件统计 int cnt count_if(v.begin(), v.end(), [](int x) { return x % 2 0; }); // for_each 遍历 for_each(v.begin(), v.end(), [](int x) { cout x ; }); // remove_if 条件删除 v.erase(remove_if(v.begin(), v.end(), [](int x) { return x 3; }), v.end()); // transform 转换 vectorint doubled(v.size()); transform(v.begin(), v.end(), doubled.begin(), [](int x) { return x * 2; });二、作为回调函数// 自定义排序时传入 sort(v.begin(), v.end(), [](int a, int b) { return abs(a) abs(b); // 按绝对值排序 }); // 配合 priority_queue auto cmp [](int a, int b) { return a b; }; // 小顶堆 priority_queueint, vectorint, decltype(cmp) pq(cmp);三、配合 function 存储#include functional #include map // 用 function 包装 Lambda functionint(int, int) add [](int a, int b) { return a b; }; cout add(3, 5) endl; // 8 // 函数表用 map 存储不同操作 mapchar, functionint(int, int) ops; ops[] [](int a, int b) { return a b; }; ops[-] [](int a, int b) { return a - b; }; ops[*] [](int a, int b) { return a * b; }; cout ops[](3, 5) endl; // 8四、配合线程#include thread int x 10; // 线程中使用 Lambda thread t([x] { x; cout 线程内 x x endl; }); t.join(); cout 主线程 x x endl; // 11第六部分Lambda vs 仿函数 vs 函数指针对比项函数指针仿函数Lambda代码位置函数定义在外部类定义在外部就地定义捕获变量❌✅ 通过成员变量✅ 通过捕获列表内联优化❌ 难以内联✅ 可内联✅ 可内联类型函数指针类型有具体类名匿名类型复用性✅✅❌ 匿名不可复用简洁性❌❌✅使用场景与 C 接口交互需要复用/带状态一次性逻辑首选第七部分注意事项1. 悬空引用// ❌ 危险引用的变量已被销毁 functionvoid() createFunc() { int x 10; return [x] { cout x; }; // x 在函数结束后被销毁 } // ✅ 安全值捕获 functionvoid() createFunc() { int x 10; return [x] { cout x; }; // x 被拷贝到 Lambda 内部 }2. 全局变量不需要捕获int global 10; auto f [] { return global; }; // OK全局变量可以直接访问3. 静态变量不需要捕获static int s 10; auto f [] { return s; }; // OK静态变量可以直接访问总结一、核心语法速查写法含义[]{}最简单的 Lambda[x]值捕获 x[x]引用捕获 x[]值捕获所有[]引用捕获所有[, x]默认值捕获x 引用[this]捕获 this 指针mutable允许修改值捕获的变量- int显式返回类型二、一句话记忆Lambda 是匿名的仿函数对象通过[捕获]访问外部变量(参数)接收输入{函数体}实现逻辑。值捕获是定义时拷贝引用捕获是运行时访问。STL 算法中用 Lambda 代替函数指针和仿函数是 C 最常用的编程模式之一。