简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
Lambda表达式完整的声明格式如下:
[capture list] (params list) mutable exception-> return type { function body }
各项具体含义如下:
[capture list]
:捕获外部变量列表,捕捉列表总是出现在Lambda函数的开始处,作为编译器判断lambda表达式的特征,这部分必须存在,不能省略。(params list)
:形参列表可有可无 (也称为lambda声明符),就是正常的函数输入参数,没有参数时()可以省略。mutable
指示符:可有可无,用来说用是否可以修改捕获的变量,按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身),默认值传递为constexception
:表示Lambda表达式可以抛出指定类型的异常->return type
:返回值类型,当返回值为void,可省略{ function body }
:lambda 体(函数体)
Lambda 以捕获子句开头。 它指定捕获的变量以及捕获是通过值还是通过引用来捕获。 具有符号 (&)前缀的变量通过引用访问,不包含它的变量通过值访问。
空capture子句
[]
指示lambda
表达式的主体不访问封闭范围中的变量。
可以使用捕获-默认模式来指示如何捕获 lambda 体中引用的任何外部变量:
[&]
表示引用的所有变量都按引用捕获[=]
表示它们是通过值捕获的- 可以使用默认捕获模式,然后为特定变量显式指定相反的模式
例如,如果lambda
体通过引用访问外部变量total
并通过值访问外部变量factor
,则以下capture
子句等效:
[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
<!--[=, &total]-->
[&total, =]
此外,我们还可以省略其中的某些成分来声明“不完整”的Lambda表达式,常见的有以下几种:
序号 | 格式 |
---|---|
1 省略mutable exception | [capture list] (params list) -> return type {function body} |
2 省略return type | [capture list] (params list) {function body} |
3 省略params list | [capture list] {function body} |
代码实例
示例1:
下面这段代码是Codec2Client::createComponent
中创建component的一段:
media/codec2/hidl/client/client.cpp
mBase1_0->createComponent(
name,
hidlListener,
ClientManager::getInstance(),
[&status, component, hidlListener](
Status s,
const sp<hardware::media::c2::V1_0::IComponent>& c) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
return;
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
});
capture list是:[&status, component, hidlListener]
,status,component,hidlListener三个是外部变量
param list是:(Status s, const sp<hardware::media::c2::V1_0::IComponent>& c)
,s
和c
是形参列表,在mBase1_0->createComponent
这个函数内部调用lambda表达式的时候会传入具体的参数,这里,可以把lambda表达式理解为函数指针,内部调用lambda表达式就和使用函数指针是一样的。
函数体是:
{
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
return;
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
}
示例2:
media/codec2/hidl/client/client.cpp
std::shared_ptr<Codec2Client::Component>
Codec2Client::CreateComponentByName(
const char* componentName,
const std::shared_ptr<Listener>& listener,
std::shared_ptr<Codec2Client>* owner,
size_t numberOfAttempts) {
std::string key{"create:"};
key.append(componentName);
std::shared_ptr<Component> component;
c2_status_t status = ForAllServices(
key,
numberOfAttempts,
[owner, &component, componentName, &listener](const std::shared_ptr<Codec2Client> &client)-> c2_status_t {
c2_status_t status = client->createComponent(componentName, listener, &component);
if (status == C2_OK) {
if (owner) {
*owner = client;
}
} else if (status != C2_NOT_FOUND) {
// LOG ...
}
return status;
});
if (status != C2_OK) {
// LOG ...
}
return component;
}
lambda表达式为:
[owner, &component, componentName, &listener](const std::shared_ptr<Codec2Client> &client)-> c2_status_t {
c2_status_t status = client->createComponent(componentName, listener, &component);
if (status == C2_OK) {
if (owner) {
*owner = client;
}
} else if (status != C2_NOT_FOUND) {
// LOG ...
}
return status;
});
[owner, &component, componentName, &listener]
是capture list
(const std::shared_ptr<Codec2Client> &client)
是形参列表,参数client在ForAllServices函数中调用这个表达式的时候被传入
-> c2_status_t
是返回值类型
在ForAllServices
函数中,第三个参数是通过std::function
定义的一个函数指针,predicate是指针名,而前面的lambda和predicat类型一样,lambda表达式作为可调用对象,通过predicate调用。
c2_status_t Codec2Client::ForAllServices(
const std::string &key,
size_t numberOfAttempts,
std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>predicate) {
c2_status_t status = C2_NO_INIT; // no IComponentStores present
// ...
}