【学习笔记】QT从入门到实战完整版(Lambda)(2)
Lambda
Lambda 表达式很有意思,相信很多人初次见到 Lambda 表达式都会不能理解有什么用,我也一样,看了视频教程之后,突然意识到,Lambda 真的是太好用了,它可以在某些情况下可以很大程度上简化代码。
应用场景
下面的代码给我的启发:实现通过信号槽的方式实现点击按钮时,触发修改按钮的名字为“停止”。connect 的最后一个参数其实是函数指针,当按钮触发了 clicked 信号时,将会调用该函数指针,那么借助 Lambda 就不需要重新另外定义一个成员函数来作为参数传入。
void Widget::testLambda()
{
QPushButton *pButton = new QPushButton();
pButton->setParent(this);
pButton->setText("启动");
connect(pButton, &QPushButton::clicked, this, [=](){
pButton->setText("停止");
});
}
可以自己写一个函数回调的方式来对比
#include <iostream>
void onEvent()
{
printf("onEvent\n");
}
void notice(void (*pfunc)())
{
pfunc();
}
int main(int argc, char *argv[])
{
notice(onEvent);
return 0;
}
使用 Lambda 的方式,可以看到代码简化了
#include <iostream>
void notice(void (*pfunc)())
{
pfunc();
}
int main(int argc, char *argv[])
{
notice( [](){printf("Lambda2\n");} );
return 0;
}
介绍说明
从上面的例子可以看到,Lambda 其实本质就是一个函数,只不过这个函数没有名字,所以也叫匿名函数。适合在一些需要传递以函数为参数的表达式中,而函数本事的实现只有几句代码,可以不必另外声明定义函数,直接使用 Lambda 即可。
Lambda 原型说明:
[外部变量访问方式说明符] (参数表) 修饰符 ->返回值类型 {函数体} ()
Lambda 原型解析:
[外部变量访问方式说明符] :
用于确定 Lambda 函数体可以用何种方式去访问外部成员
- [] 中括号里面为空,即表示不访问任何外部成员变量。
- [&] 以引用方式使用 Lambda 所在作用范围内所有可见的局部变量(包括Lambda所在类的 this)。
- [=] 以值传递方式使用 Lambda 所在作用范围内所有可见的局部变量(包括Lambda所在类的 this)。
- [=, &a] 除了a以引用传递方式使用,其他的所有变量以值传递方式使用。
- [a] 只取a,并且以值传递方式使用。
- [this] 取 Lambda 所在的类中的 this 指针。如果已经使用了 & 或者 = 就默认添加此选项。
代码示例:
void Widget::showString(char *pString)
{
qDebug() << pString;
}
void Widget::testLambda()
{
int a = 1;
int b = 2;
// [] 方式
qDebug() << "[] 方式";
[]()
{
// int x = a + b; // 会报错, 因为 a、b 不可见
qDebug() << "调用中:";
}();
// [&] 方式
qDebug() << "\n[&] 方式";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[&]()
{
a = 5;
b = 3;
qDebug() << "调用中: "<< "a:" << a << " b:" << b;
this->showString("[&] 方式使用成员函数 showString()");
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
// [=] 方式
qDebug() << "\n[=] 方式";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[=]()
{
// a = 5; // 会报错, 变量默认为只读属性, 需要使用 mutable 修饰符才可以修改
qDebug() << "调用中: "<< "a:" << a << " b:" << b;
this->showString("[] 方式使用成员函数 showString()");
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
// [=, &a] 方式
qDebug() << "\n[=, &a] 方式";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[=, &a]()
{
a = 16;
// b = 7; // 会报错, b变量默认为只读属性, 需要使用 mutable 修饰符才可以修改
qDebug() << "调用中: "<< "a:" << a << " b:" << b;
this->showString("[=, &a] 方式使用成员函数 showString()");
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
// [a] 方式
qDebug() << "\n[a] 方式";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[a]()
{
//a = 16; // 会报错, a变量默认为只读属性, 需要使用 mutable 修饰符才可以修改
//qDebug() << "调用中: "<< "a:" << a << " b:" << b; // 会报错, b 变量不可见
// this->showString("[a] 方式使用成员函数 showString()"); // 会报错, this 不可见
qDebug() << "调用中: "<< "a:" << a;
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
// [this] 方式
qDebug() << "\n[this] 方式";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[this]()
{
// qDebug() << "调用中: "<< "a:" << a << " b:" << b; //会报错 a、b 都不可见
this->showString("[this] 方式使用成员函数 showString()");
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
}
运行结果
[] 方式
调用中:
[&] 方式
调用前: a: 1 b: 2
调用中: a: 5 b: 3
[&] 方式使用成员函数 showString()
调用后: a: 5 b: 3
[=] 方式
调用前: a: 5 b: 3
调用中: a: 5 b: 3
[] 方式使用成员函数 showString()
调用后: a: 5 b: 3
[=, &a] 方式
调用前: a: 5 b: 3
调用中: a: 16 b: 3
[=, &a] 方式使用成员函数 showString()
调用后: a: 16 b: 3
[a] 方式
调用前: a: 16 b: 3
调用中: a: 16
调用后: a: 16 b: 3
[this] 方式
调用前: a: 16 b: 3
[this] 方式使用成员函数 showString()
调用后: a: 16 b: 3
(参数表) :
用于确定 Lambda 传入那些变量作为参数提供给 Lambda 函数体使用,如果没有可以省略 “()” 括号。
#include <iostream>
void onEvent(int type)
{
printf("onEvent:%d\n", type);
}
void notice(void (*pfunc)(int type), int type)
{
pfunc(type);
}
int main(int argc, char *argv[])
{
// 传统的方式, 回传参数
notice(onEvent, 5);
// lambda 方式 一 , 回传参数
notice([](int type) {printf("Lambda :%d\n", type); }, 15);
// lambda 方式 二 , 回传参数
auto func = [](int c, int d)
{
printf("AutoFunc: c: %d d:%d\n",c ,d);
};
// 调用
func(8, 9);
return 0;
}
修饰符:
如果没有修饰符则可以省略不写
mutable:
用于修饰 [外部变量访问方式说明符] 中列举的按值传递方式的变量时,可以修改其拷贝值。
相当于 void func(const int a, const int b) 变为 void func(int a, int b)
当有此修饰符时,引入的外部变量不能为空。
void Widget::testLambda()
{
int a = 1;
int b = 2;
// mutable
qDebug() << "\nmutable";
qDebug() << "调用前: " << "a:" << a << " b:" << b;
[a, b] () mutable
{
a = 16; // 由于是值传递,a 其实是 lambda 函数体内的局部变量,所以修改的只是 a 的拷贝
b = 100;
qDebug() << "调用中: "<< "a:" << a << " b:" << b; // 会报错, b 变量不可见
}();
qDebug() << "调用后: " << "a:" << a << " b:" << b;
}
mutable
调用前: a: 1 b: 2
调用中: a: 16 b: 100
调用后: a: 1 b: 2
exception:
说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f()throw(X, Y)
->返回值类型 :
说明 lambda 函数体可以返回什么样类型的值,实际测试中似乎无论什么情况都可以省略,编译器会自动推测出类型。
#include <iostream>
void notice(int (*pfunc)(int a, int b), int aa, int bb)
{
printf("notice:%d\n",pfunc(aa, bb));
}
int main(int argc, char *argv[])
{
// lambda, 回传参数
notice(
[](int a, int b)
{
printf("回调隐式返回类型: a:%d b:%d a+b:%d\n", a, b, a + b);
return a + b;
},
10, 15);
puts("");
// lambda, 回传参数
notice(
[](int a, int b)->int
{
printf("回调显式返回类型: a:%d b:%d a+b:%d\n", a, b, a + b);
return a + b;
},
10, 15);
puts("");
// lambda, 显式返回类型
auto func = [](int c, int d)->int
{
printf("显式返回类型: c:%d d:%d c+d:%d\n",c ,d, c + d);
return c + d;
};
// 调用
printf("func:%d\n", func(20, 10));
puts("");
// lambda, 隐式返回类型(视频中说只有一处才可以省略,但实际做的实验发现都可以)
auto func1 = [](int c, int d)
{
printf("隐式返回类型: c:%d d:%d c+d:%d\n", c, d, c + d);
if (c > 3)
return c + d;
else
return c;
};
// 调用
printf("func1:%d\n", func1(50, 10));
return 0;
}
{函数体} :
实际具体的实现,一般都只有几句代码。
():
最后这一个括号其实代表的是调用的意思,当需要执行时,加上括号即可。
// 只是定义, 并未调用
[]()
{
printf("11111111111111\n");
};
// 定义了且被调用了
[]()
{
printf("11111111111111\n");
}();
// 最简单的 lambda 表达式
[] {puts("lambda..."); };
【学习笔记】QT从入门到实战完整版(Lambda)(2)的更多相关文章
- 2579页阿里P8Android学习笔记在互联网上火了,完整版开放下载
笔记作者:来自于阿里P8级大神: Mark 笔记特点:条理清晰,理论+实战+源码,含图像化表示更加易懂. 内容概要:Android 相关,性能优化,Java 相关,Kotlin 相关,网络相关,插件化 ...
- Hadoop学习笔记(1) ——菜鸟入门
Hadoop学习笔记(1) ——菜鸟入门 Hadoop是什么?先问一下百度吧: [百度百科]一个分布式系统基础架构,由Apache基金会所开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序. ...
- iOS学习笔记-地图MapKit入门
代码地址如下:http://www.demodashi.com/demo/11682.html 这篇文章还是翻译自raywenderlich,用Objective-C改写了代码.没有逐字翻译,如有错漏 ...
- tensorflow学习笔记二:入门基础 好教程 可用
http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础 TensorFlow用张量这种数据结构来表示所有的数据.用一 ...
- 电子书下载:Delphi XE 5 移动开发入门手册(完整版)
更多电子书请到: http://maxwoods.400gb.com 下载:Delphi XE5移动开发入门手册(完整版)
- spark学习笔记总结-spark入门资料精化
Spark学习笔记 Spark简介 spark 可以很容易和yarn结合,直接调用HDFS.Hbase上面的数据,和hadoop结合.配置很容易. spark发展迅猛,框架比hadoop更加灵活实用. ...
- Android学习笔记(二十一)——实战:程序数据共享
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 我们继续在Database项目的基础上继续开发,通过内容提供器来给它加入外部访问接口.首先将 MyDataba ...
- Android学习笔记(十五)——实战:强制下线
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 实现强制下线功能的思路也比较简单,只需要在界面上弹出一个对话框, 让用户无法进行任何其他操作, 必须要点击对话 ...
- Android学习笔记(十二)——实战:制作一个聊天界面
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...
- SQL学习笔记——SQL初入门,Ubuntu下MySQL的安装
刚开始接触sql,于是准备在Ubuntu下学习sql,就跟着itercast的sql教程开始入门了. 下面只是我个人的记录,高手请绕道: 一. 在安装之前,我们可以用下面这个命令通过开放端 ...
随机推荐
- 初识vue3.0
vue3.0 源码组织方式的变化 采用ts重写 独立的功能模块提取到单独的包中 90%的api兼容Vue2.x Composition API 组合api 解决vue2.x options api 开 ...
- 从 WinDbg 角度理解 .NET7 的AOT玩法
一:背景 1.讲故事 前几天 B 站上有位朋友让我从高级调试的角度来解读下 .NET7 新出来的 AOT,毕竟这东西是新的,所以这一篇我就简单摸索一下. 二:AOT 的几个问题 1. 如何在 .NET ...
- CentOS 7.x字符界面安装图形界面方法
1. 配置好yum源,可以使用光盘镜像源,也可以使用网络源. 阿里源下载示例: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.ali ...
- <三>使用类模板实现STL Vector
使用类模板实现STL Vector,点击查看代码 #include <iostream> using namespace std; template<typename T> c ...
- DP?
杨斌涵//aad69d38 分治优化DP 分治优化1D/1D dp 对于一类 \[f(x) = \min_{k = y}^{x - 1} w(l, r) \] 即所有 \(w(l,r)\) 事先已知, ...
- layui文件上传+ThinkPHP
1.前端html代码 <div class="layui-form-item"> <label class="layui-form-label" ...
- 基于Sklearn机器学习代码实战
LinearRegression 线性回归入门 数据生成 为了直观地看到算法的思路,我们先生成一些二维数据来直观展现 import numpy as np import matplotlib.pypl ...
- 痞子衡嵌入式:MCUXpresso IDE下高度灵活的FreeMarker链接文件模板机制
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下高度灵活的FreeMarker链接文件模板机制. 痞子衡之前写过一篇文章 <MCUXpresso I ...
- SerialException:Cannot configure port something went wrong
完整报错 SerialException:Cannot configure port something went wrong, Original message: OSError(22, '参数错误 ...
- python3 利用当前时间、随机数产生一个唯一的数字作为文件名
一.python3 利用当前时间.随机数产生一个唯一的数字作为文件名 代码如下: #-*-coding:utf-8-*- #python3自动生成文件名 from datetime import * ...