C++
在 C++ 中,Lambda 表达式(也称为匿名函数或闭包)是一个可以捕获局部变量的简短函数对象。Lambda 表达式可以定义在任何需要函数对象或可调用对象的地方,它们特别适用于需要定义小型、一次性的函数对象的情况。
下面是一个 Lambda 表达式的基本结构和解析:
- 基本语法:
[capture](parameters) -> return-type { body }
[capture]
:捕获子句,用于指定 Lambda 表达式体中可以使用哪些外部变量(按值或按引用)。(parameters)
:参数列表,与普通函数相同。-> return-type
:可选的返回类型说明符,用于指定 Lambda 表达式的返回类型。如果 Lambda 表达式的体只包含一个返回语句,并且编译器能够推断出返回类型,则可以省略该部分。{ body }
:Lambda 表达式的主体,包含函数体的代码。
- 捕获子句:
捕获子句决定了哪些外部变量可以在 Lambda 表达式的体内被访问。捕获可以是按值(=
)或按引用(&
),或者是显式指定变量(例如 [x, &y]
)。
* `[]`:不捕获任何变量。
* `[=]`:以值捕获所有外部变量。
* `[&]`:以引用捕获所有外部变量。
* `[x, &y]`:按值捕获 `x`,按引用捕获 `y`。
- 使用示例:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 使用 Lambda 表达式对 vector 中的每个元素乘以 2
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });
// 输出结果
for (int i : v) {
std::cout << i << ' ';
}
// 输出:2 4 6 8 10
return 0;
}
在这个例子中,我们使用了一个简单的 Lambda 表达式 [](int x) { return x * 2; }
作为 std::transform
的第四个参数。这个 Lambda 表达式接受一个整数参数 x
,并返回 x * 2
。
Lambda 表达式提供了一种简洁、灵活的方式来定义和使用小型函数对象,使 C++ 代码更加简洁和易读。
Qt
在Qt中,Lambda表达式是一种方便的方式来定义匿名函数,通常用于连接信号和槽以及其他需要函数对象的地方。Lambda表达式提供了一种更简洁的方式来编写函数对象,而不必显式地编写函数定义。下面是对Qt中Lambda表达式的解析:
[ captures ]( parameters ) mutable(optional) noexcept(optional) -> return_type(optional) { body }
- captures:捕获列表,用于捕获外部变量。可以是值捕获、引用捕获或混合捕获。
- parameters:参数列表,用于指定Lambda函数的参数。
- mutable:可选关键字,指示Lambda函数是否可以修改其捕获的变量。
- noexcept:可选关键字,指示Lambda函数是否不会抛出异常。
- return_type:可选的返回类型说明符,用于指定Lambda函数的返回类型。
- body:Lambda函数的主体,即函数体。
Lambda表达式的使用
Lambda表达式通常用于连接信号和槽,以及在需要函数对象的地方,例如STL算法和标准库函数中。
连接信号和槽
在Qt中,Lambda表达式通常用于连接信号和槽,如下所示:
QObject::connect(sender, &Sender::signal, [](int value) {
qDebug() << "Received value:" << value;
});
这里,Lambda表达式作为槽函数,用于处理信号发出时的操作。
STL算法和标准库函数
Lambda表达式也可以用于STL算法和标准库函数,例如std::sort:
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5};
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return a < b;
});
这里,Lambda表达式定义了排序的比较函数。
Lambda表达式与捕获列表
Lambda表达式的捕获列表允许您在Lambda函数内部访问外部变量。捕获列表可以是值捕获、引用捕获或混合捕获。
值捕获
int a = 10;
auto lambda = [a]() {
qDebug() << "Captured value:" << a;
};
在这个例子中,Lambda表达式通过值捕获变量a,这意味着在Lambda函数内部使用的a的值是捕获时的值。
引用捕获
int b = 20;
auto lambda = [&b]() {
qDebug() << "Captured reference:" << b;
};
在这个例子中,Lambda表达式通过引用捕获变量b,这意味着在Lambda函数内部使用的b是外部变量b的引用。
混合捕获
int c = 30;
auto lambda = [c]() mutable {
qDebug() << "Captured value before modification:" << c;
c = 40;
qDebug() << "Captured value after modification:" << c;
};
在这个例子中,Lambda表达式通过值捕获变量c,但由于指定了mutable关键字,Lambda函数可以修改捕获的变量。
Lambda表达式与返回类型推断
Lambda表达式可以根据其返回语句的类型来推断返回类型,也可以显式指定返回类型。
auto lambda = [](int a, int b) { return a + b; }; // 自动推断返回类型
int sum = lambda(3, 4); // sum = 7
auto lambda2 = [](int a, int b) -> double { return a + b; }; // 显式指定返回类型为double
double result = lambda2(3, 4); // result = 7.0
Lambda表达式与异常规范
Lambda表达式可以指定是否会抛出异常。
auto lambda = []() noexcept {
qDebug() << "This lambda will not throw exceptions.";
};
Lambda表达式的限制
虽然Lambda表达式提供了许多方便的功能,但也有一些限制。Lambda函数不能是虚函数,也不能包含goto语句。此外,在Lambda表达式内部不能声明其它的Lambda表达式。