一、Lambda 表达式本质就是匿名函数,是 C++11 增加的新特性,所以使用 lambda 表达式的时候,需要在 Qt 项目文件(.pro) 中添加 CONFIG += C++11:
![](https://img-blog.csdnimg.cn/20200305090306927.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5MzMxMzY1,size_16,color_FFFFFF,t_70)
二、Lambda 表达式的语法格式为:
[capture](params) mutable ->return-type{statement}
1、[capture]:捕捉列表,作用是将外部变量传入到 lambda 表达式的内部;也是 lambda 的引出符,编译器根据该引出符判断下面的代码是 lambda 表达式;
2、(params):参数列表,作用是将参数传入到 lambda 表达式内部;如果没有参数可省略;
3、mutable :可变参数修饰符,默认情况下外部变量传入到 lambda 表达式内部后是只读的,mutable 的作用就是将 lambda 表达式内部的只读变量 变成可读可写的;mutable 也可以省略;
4、->return-type:返回类型,如果 lambda 表达式没有返回值,也可以省略;
5、{}:函数体,和普通函数一样;
三、一个最简单的 lambda 表达式:修改 mywidget.cpp 文件为:
#include "mywidget.h"
#include <QPushButton>
#include <QDebug>
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->resize(400, 300);
// 创建按钮对象,并通过构造函数指定父对象
QPushButton *btn = new QPushButton(this);
btn->setText("lamda表达式");
btn->move(100, 80);
/*
* 点击按钮的时候,执行 lambda 表达式,输出一句话;
*/
connect(btn, &QPushButton::clicked,
[] // lambda 表达式的引出符,编译器根据 [] 判断下面的代码是 lambda 表达式
{
// 函数体:和普通函数一样
qDebug() << "我是 lamda 表达式输出的";
}
);
}
四、[capture]:捕捉列表
1、[] 中可以是某个(些)具体的变量名,表示 lambda 表达式内部只能获取到 [] 中指定的变量:
int a = 10, b = 20;
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
// 如果 [] 中是某个具体的变量名,那 lambda 表达式
// 内部只能获取该变量,不能获取到其他变量;
[a]
{
qDebug() << "a=" << a;
// 因为 [] 里只有一个变量 a,所以 lambda 内部只能获取
// 到变量a,不能获取到变量 b;下面输出语句编译会报错;
// qDebug() << "b=" << b;
}
);
[] 中也可以同时存在多个变量名,以逗号分隔:
int a = 10, b = 20, c = 30;
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
[a, b, c]
{
// lambda 表达式可以获取 [] 中的所有变量
qDebug() << "a=" << a;
qDebug() << "b=" << b;
qDebug() << "c=" << c;
}
);
2、[] 中可以是 =,表示将外部所有局部变量,以及类中所有成员以值传递方式传入到 lambda 表达式内部:
int a = 10;
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
[=]
{
// [=] 表示 lambda 表达式内部可以获取外部所有局部变量,以及类中所有的成员;
qDebug() << "a=" << a;
btn->setText("123");
}
);
3、[] 中可以是 this,表示将类中所有成员,不包括局部变量,以值传递方式传入到 lambda 表达式内部:
int a = 10; // 局部变量
b = 20; // 在头文件中定义的成员变量
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
[this]
{
// [this] 表示将类中所有成员,不包括局部变量,以值传递方式传入到 lambda 表达式,
// 所以在 lambda 表达式内部只能获取到 b,不能获取到 a;
qDebug() << "b=" << b;
// qDebug() << "a=" << a;
}
);
4、[] 中可以是 &,表示将外部所有局部变量,不包括类中成员,以引用方式传递到 lambda 表达式内部:但是不建议使用 &,因为会出现内存问题,比如:
![](https://img-blog.csdnimg.cn/20200305101401454.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5MzMxMzY1,size_16,color_FFFFFF,t_70)
所以,总结上面捕获列表的用法可知,[] 中最常用的是 [=];
五、(params):参数列表
查看文档可知,按钮的 clicked 信号有一个参数,如下:
![](https://img-blog.csdnimg.cn/20200305102449792.png)
现在,我们把这个参数传递到 lambda 表达式内部:
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
// 将 &QPushButton::clicked 信号的参数(bool isChecked)传入到 lambda 表达式内部
[=](bool isChecked)
{
qDebug() << "isChecked=" << isChecked;
}
);
六、mutable :可变参数修饰符
int a = 10; // 局部变量
/*
* 点击按钮的时候,执行 lambda 表达式
*/
connect(btn, &QPushButton::clicked,
[=]()mutable
{
qDebug() << "a=" << a;
// mutable:可变参数修饰符,如果没有 mutable 关键字,传入 lambda 内部
// 的变量是只读的,下面赋值的语句会报错;
// 使用 mutable 之后,变量就会变成可读可写的,才可以修改变量的值;
a += 10;
}
);
七、->return-type:返回类型
前面说到 [=] 是将外部变量 以值传递的方式 传入到 lambda 表达式内部,值传递的变量在 lambda 表达式内部修改之后,外部变量的值不会变;
如果想在 lambda 表达式内部修改外部变量的值,需要在修改之后再将变量返回出去;
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->resize(400, 300);
// 创建按钮对象,并通过构造函数指定父对象
QPushButton *btn = new QPushButton(this);
btn->setText("lamda表达式");
btn->move(100, 80);
QPushButton *btn2 = new QPushButton(this);
btn2->setText("lamda表达式2");
btn2->move(100, 150);
int a = 10; // 局部变量
// 在外部定义一个 lambda 表达式,即匿名函数;
// 注意:此处的 auto 理论上表示自动适配变量的类型,但是我改成
// int 就会报错,改成其他类型也不行,只有 auto 可以编译通过;
// [=]:表示将外部变量以值传递方式传入到 lambda 表达式内部;
// (QString str):表示传入 lambda 表达式的参数;
// mutable:表示将外部变量传入 lambda 内部以后变成可读可写的;
// ->int:表示 lambda 表达式返回值的类型;
auto func = [=](QString str)mutable->int
{
qDebug() << "a=" << a;
qDebug() << "str=" << str;
// 在 lambda 表达式内部修改变量的值,然后再传出去
a += 10;
return a;
};
connect(btn, &QPushButton::clicked,
[=]()mutable
{
// 调用外部定义的 lambda 表达式,并接收返回的值:
int result = func("add");
qDebug() << "lambda表达式返回的值:" << result;
}
);
connect(btn2, &QPushButton::clicked,
[=]()
{
// 以值传递的方式将变量 a 传入到 lambda 表达式内部,
// 在表达式内部修改变量的值,外部变量的值不会变化:
qDebug() << "在表达式内部修改变量值之后,外部变量的值:" << a;
}
);
}
运行结果:
![](https://img-blog.csdnimg.cn/20200305113318439.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5MzMxMzY1,size_16,color_FFFFFF,t_70)