首页 > 代码库 > 【C++】【lambda】lambda函数介绍和个人理解(1)——初识lambda

【C++】【lambda】lambda函数介绍和个人理解(1)——初识lambda

导航:

lambda函数介绍和个人理解(1)——初识lambda

lambda函数介绍和个人理解(2)——lambda与仿函数

lambda函数介绍和个人理解(3)——lambda的语法甜点

什么是lambda函数?

         其实,lambda函数我个人更愿意称为lambda运算(lambdacalculus),它是用来表示一种匿名函数。这个严格意义上属于“函数式编程”(Functional Programming)的范畴。当然还是先解释下函数式编程的概念的好。按照当时冯·诺依曼机器的基本计算模型,所谓通过一条条机器指令逐步把输入数据加工成最终的计算结果,而在计算过程中会有大量的内存单元被反复修改。函数式编程的思想就是把所有的这些状态看做一个全集,程序的基本组成部分就是这些状态之间的映射,其实也就是广义上的函数(广义上的函数的概念是,只要存在广义上的集合A,B,并且存在从A映射到B的映射关系,这个映射关系就被称作广义上的函数。在计算机编程领域,广义的函数包含过程,也就是Pascal语言中有名的Procedure)。通过这些函数之间的复杂运算,把输入数据映射到最终结果,这就是函数式编程。回到一开始的lambda运算,lambda运算其实我们就可以理解成一个简单的运算方法,就像加法减法乘法除法一样,就是一个运算规则:

 

                  lambda运算 := 传入数据 –>一系列的运算 -> 传出结果

         这就是神龙见首不见尾的lambda运算。他其实就是一个运算规则,说的高雅点,叫做lambda算子(lambda operator)。这时候,如果我们结合理解函数式编程的理念,我们就知道为什么这个东西叫lambda函数了,因为满足我上文中所讲到的广义函数的定义啊!广义集合A(传入数据)和广义集合B(传出数据)还有他们的映射关系(一系列的运算),所以其实这个运算就是一个函数。至此,我们终于了解了为什么叫lambda函数。

 

“匿名的”?匿名的!

         可是为什么又要提到,lambda函数是一个匿名函数呢?什么叫“匿名的”函数呢?一般而言,我们都知道,所谓的函数,不论是哪一种编程语言,都要给自定义的函数进行命名处理,看似天经地义。然而只有一种例外,那便是lambda函数。lambda函数没有名字,对的,没有函数名。你可能要问:不对啊?你刚刚不是说,这个lambda函数满足上述的广义函数定义,他不就是一个函数么?

         其实这个问题不难解决。没错,他是函数,但没有任何人规定:“一个函数,必须有一个名字与其对应。”你肯定会说,呵呵!你又跟我玩文字游戏。那你解释下lambda函数他究竟是个什么?OK!交给我了:

         先给大家看几个典型的lambda函数使用的例子:

/****
    *@PoloShen
    *Title: lambda 01
    */
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main(){
    auto total = [](int a, int b)->int{return a+b; };    //生成一个lambda函数,求两数之和
    cout<<total(3,5)<<endl;                                //输出8, 3+5=8
    vector<int> nums;
    for (int i = 0; i < 5; i++) nums.push_back(i);        //将nums初始化
    auto print = [&]{                                    //生成一个lambda函数,用于打印nums
        for (auto s: nums){cout<<s<<"\t";}
        cout<<endl;
    };
    print();                                            //打印nums
    for_each(nums.begin(), nums.end(), [=](int &i){        //将nums每一个元素加10
                i += 10;
            });
    print();                                            //再次打印nums
    return 0;
}
//编译选项:: g++ -std=c++11 lambda01.cpp

对我们这些程序员而言,lambda函数是一个“不定态事物”,它既可以写成一个类似变量的形式,又可以写在函数指针的接口上,还可以当做一个类似于“局部函数”的东西使用。但实际上,从最简单易懂的地方去理解,lambda函数只会出现在两个地方:变量等号后面,还有函数指针的接口上。例子1中,变量total和变量print后面就分别接了一个lambda函数,分别用于计算两数之和和打印数表;另外一个就是在for_each方法中的那个lambda函数,用于使数表中的元素值增加10。看上去,total、print就像他们的函数名一样,但实际上则不然。严格意义上,他们依然是变量,只不过这个类型很复杂;但是实际上,他们就是一个“传令兵”,只是在引用中免得你找不到而已。更多情况下,按照所谓的函数式编程的理念,“万物皆函数”(笑),lambda函数更多的应当出现在最需要他的地方,也就是有函数指针的地方。所以不必在意他是什么名字,只需要考虑如何好好地完成任务即可。就比方说我们看到的在for_each中所使用的lambda函数一样,不用关心他的名字是什么,我们关心的是实现这个运算的方法。如此一来就不难理解lambda函数的匿名性了。

         至此,最难啃的两块骨头已经被我们吃下去了,剩下的就是慢慢消化。

 

lambda函数的语法定义

lambda函数的语法定义如下:

[capture](parameters) mutable -> return-type{statsment}

其中

  • [capture]捕捉列表。捕捉列表总是出现在lambda函数的开始处。事实上,[]是lambda函数的引出符。编译器根据该引出符判断接下来的代码是否是lambda函数。捕捉列表能够捕捉上下文中的变量以供lambda函数使用。
  • (parameters)参数列表。其实就是和普通额函数参数列表一致。如果不需要参数传递,则可以连同括号一起省略。
  • mutablemutable修饰符。默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略,即使参数为空。
  • ->return-type返回类型。同追踪返回类型形式声明函数的返回类型。出于方便,不需要返回值的时候也可以连同符号->一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器自行对返回类型进行推导。
  • {statsment}函数体。内容与普通函数一样,不过除了可以使用的参数之外,还可以使用所有捕获的变量。

 

以上便是lambda函数的定义了。和其他常规的函数不同,lambda函数可以去使用通过捕获列表中的数据。语法上,捕获列表有多个捕捉项组成,并以逗号分隔。以下便是捕获列表的形式:

  • [var]表示值传递方式捕获变量var
  • [=]表示值传递方式捕获所有父作用域的变量(包括this)
  • [&var]表示引用传递方式捕获变量var
  • [&]表示引用传递方式捕获所有父作用域的变量(包括this)
  • [this]表示值传递方式捕获当前的this指针

         但是请注意!捕获列表不允许变量的重复传递。比如说:

  • [=, a] 重复捕获a,错误。
  • [&, &this] 重复捕获this,错误

         Ok,到这里,所有语法上的lambda函数说明都完成了,给一些简单的例子,然后慢慢畅游吧!

/****
    *@PoloShen
    *Title: lambda 02
    */
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main(){
    []{};                                                //最简lambda函数
    int a = 3, b = 4;
    [=]{return a+b;};                                    //省略参数列表和返回类型
    auto fun1 = [&](int c){b = a + c;};                    //省略了返回类型,无返回值
    auto fun2 = [=, &b](int c)->int{return b += a + c;};//各部分都很完整的lambda函数
    auto fun3 = [a, &b]()->int{return a+b;};            //其他传递方式的例子
    return 0;
}
//编译选项:: g++ -std=c++11 lambda02.cpp