前言
第一次接触lambda表达式还是在做leetcode的时候,有一种场景使用lambda表达式特方便,代码如下:
static bool cmp() {
...
}
void function() {
...
sort(A.begin(),A.end(),cmp);
...
}
使用STL的sort()时,要自定义排序方法。这个时候如果排序策略中要使用function()函数中的局部变量就会特别麻烦。而使用lambda表达式就可以直接进行参数传递。当然这只是lambda表达式的冰山一角,这篇文章会更详细的介绍一下,希望这篇文章能够说明白几个问题:
1.lambda表达式是什么以及如何使用?
2.lambda表达式使用时的一些原理。
因为笔者常用C++,所以就使用C++作为举例的语言啦~
1.什么是lambda表达式?
lambda表达式可理解为匿名的内联函数,内联函数就是在声明时直接进行定义了,一般有限制条件,要求函数体比较短。匿名的含义就是不需要专门为lambda表达式专门写一个函数名。
lambda函数主要有三个优点:
1)方便,可以随手定义短小精悍的函数。定义距离近
2)不用想函数名
3)定义立即执行,调用速度快,没有中间一些开销
2.如何使用lambda表达式?
先来看看lambda表达式的语法:[capture list](parameter list)->return type{function body}
主要有四部分,各部分详细定义如下:
capture list:捕获列表,lambda所在函数中定义的局部变量列表
parameter list:参数列表
return type:函数返回类型
function body:函数体
与常规函数相比,参数列表,返回类型,函数体都是比较熟悉了。那什么是捕获列表呢?这个稍后再提。注意返回类型的位置,不是在开头,这个源于lambda表达式使用尾置返回类型。
再举个实例(这个全都有):[](ListNode *x, ListNode *y)->bool {return x->val > y->val;}
虽然有四个部分,实际上参数列表和返回类型可忽略,但捕获列表和函数体必须存在
都是函数,和与普通函数的不同之处在哪里呢?
1)lambda表达式不能有默认参数,实参形参数目保持一致
2)所有参数必须有参数名
3)不支持可变参数
其他的就当结论了,第一条下面会解释一下。
3.lambda表达式中使用的一些原理
上面留了一个捕获列表的概念,我觉得这个的使用算是lambda表达式的重要环节之一。
如果没有捕获列表[],lambda表达式函数体中只能使用参数列表中变量,而没办法使用外层函数的局部变量。不过把局部变量放在捕获列表中,lambda表达式就可以使用。
lambda表达式的捕获方式可以从两个角度看:
第一个角度是:引用捕获、值捕获
第二个角度是:普通捕获 隐式捕获 混合捕获
首先介绍下各自的概念,引用捕获就是传递的是变量的引用,值捕获传递的是变量的拷贝值。类比于参数传递,很容易明白的。显示捕获就是传递具体的变量名,隐式捕获就是用一个标志代表传递所有的。具体落实到使用中的是下面这样的:
[] 空
[变量] 只传递变量 值捕获
[=] 全部实体 值捕获
[&] 全部引用 引用捕获
[&,变量名] 变量名值捕获 其余变量引用捕获
[=,变量名] 变量名引用捕获,其余变量值捕获
普通捕获:[变量名]
隐式捕获 :[=] [&]
混合方式捕获: [=,变量名] [&,变量名]
有几个重点需要强调:
1)值捕获中,被值捕获的在lambda表达式创建的时候就拷贝
2)使用引用捕获时捕获一个变量时,就必须确保被引用的对象在lambda执行的时候是存在的
3)值捕获中如果想要修改捕获列表中的某个变量值,需要加上mutable,语法就变成:[capture list] (parameter list) mutable -> return type {function body}
4)上面说返回类型可以省略,但是有条件的:1)返回值是void 2)函数体中只有return一句,编译器可以自行推断
再深挖下原理,解释一下上面留的:lambda表达式中为何必须要有实参?
当然需要实参的前提是参数列表有东西哈。原因在于lambda表达式的本质是构造类,构造的类类没有默认构造函数,赋值运算符和默认析构函数。因为没有默认构造函数,在带参函数时,必须提供实参才能正常构造。并且在类的构造中会对捕获的变量进行处理,通过值捕获的会把参数作为成员变量,而引用捕获,参数不会作为成员变量。找个一个实例参考一下:
实例来源:https://blog.youkuaiyun.com/sgh666666/article/details/89000215
因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!