首页 > 编程知识 正文

lambda表达式返回值,java表达式组成

时间:2023-05-04 11:53:37 阅读:57518 作者:1028

转自: https://blog.csdn.net/u 010984552/article/details/53634513

一段简单的Code

我也不是文艺的人。 关于Lambda的历史,以及Lambda和c的关系不太清楚。 技术人员讲究拿着代码说话。

复制代码就是:

#includeiostream

用户命名空间STD;

int main () )

{

int a=1;

int b=2;

auto func=[=,b][intc]-int{returnb=ac; (;

返回0;

}

第一次看到这个代码的时候,我直接很乱,直接不知道啊。 上面的代码,如果你理解了,下面的内容那时复习了; 如果不明白了,接下来和我一起总结吧。

基本语法

简单来说,Lambda函数是一个函数,其语法定义如下:

复制代码就是:

“捕获”可移植返回类型{ statement }

1.[捕获] :捕获列表。 捕获列表始终显示在Lambda函数的开头。 其实,[]是Lambda引出子。 编译器根据该引出子判断下一个代码是否是Lambda函数。 捕获列表捕获上下文中的变量以供Lambda函数使用。

2.(参数) :参数列表。 与常规函数的参数列表匹配。 如果不需要参数传递,可以将其与括号「()”一起省略;

3.mutable:mutable修饰符。 缺省情况下,Lambda函数始终是const函数,mutable可以取消常量性。 使用此修饰符时,不能省略参数列表(即使参数为空)。

4.-返回类型:返回类型。 将函数的返回类型声明为跟踪返回类型。 我们不需要返回值时,也可以和符号“-”一起省略。 当返回值的类型明确时,也可以省略该部分而使编译器导出返回值的类型;

5.{statement} :函数体。 内容与常规函数相同,但不仅可以使用参数,还可以使用捕获的所有变量。

与常规函数的最大区别在于,Lambda函数不仅可以使用参数,还可以从捕获列表中访问某些上下文中的数据。 特别是,捕获列表描述上下文中的哪些数据可用于Lambda,以及如何使用(传递值或传递引用)。 语法上,[]括起来的是捕获列表,捕获列表由多个捕获项目组成,并用逗号分隔。 捕获列表具有以下格式:

1.[var]表示通过值的传递方法捕捉变量var;

2.[=]值的传递方法为所有父范围的变量(包括this );

3.[var]参考传递捕获变量var;

4.[]引用传递方式捕获所有父范围的变量(包括this );

5.[this]表示传递值的方法会捕获当前的this指针。

上面介绍了作为包含Lambda函数的语句块的父范围。 通俗地说,就是包含Lambda的“{}”代码块。 上面的捕获列表还可以按如下方式组合:

1.[=,a,b]表示通过引用捕捉变量a和b,通过值传递捕捉所有其他变量。

2.[,a,this]表示通过值传递捕捉变量a和this,通过引用传递捕捉所有其他变量。

但是,捕获列表不允许重复传递变量。 以下例子是典型的重复,会导致编译时期的错误。 例如:

3.[=,a]此处按值传递捕捉所有变量,但如果重复捕捉a,则会报告错误。

4.[,this]这里已经通过引用传递捕获了所有变量。 另外,捕捉this也是反复的。

Lambda的使用

关于使用Lambda,老实说,我什么也没说。 就我个人而言,没有Lambda之前的c,我们也用得那么好。 我对缺少Lambda的c没有意见,但是现在有Lambda表达式的话,写代码会更方便。 不知道您是否记得C STL库中的仿射函数对象,仿射函数希望仿射函数对于普通函数来说可以具有初始化状态。 当声明仿射函数对象时,这些初始化状态由参数指定,并通常存储在仿射函数对象的专用变量中。 在c中,对于要求具有状态的函数,通常使用伪函数实现,如以下代码所示:

复制代码就是:

#includeiostream

用户命名空间STD;

类型编号

{

add=0,

子,

mul、

r>     divi
}type;
 
class Calc
{
    public:
        Calc(int x, int y):m_x(x), m_y(y){}
 
        int operator()(type i)
        {
            switch (i)
            {
                case add:
                    return m_x + m_y;
                case sub:
                    return m_x - m_y;
                case mul:
                    return m_x * m_y;
                case divi:
                    return m_x / m_y;
            }
        }
 
    private:
        int m_x;
        int m_y;
};
 
int main()
{
    Calc addObj(10, 20);
    cout<<addObj(add)<<endl; // 发现C++11中,enum类型的使用也变了,更“强”了                                                                                                                                              
    return 0;
}

 

现在我们有了Lambda这个利器,那是不是可以重写上面的实现呢?看代码:

 

复制代码代码如下:


#include<iostream>
using namespace std;
      
typedef enum
{     
    add = 0,
    sub,
    mul,
    divi
}type;
      
int main()
{     
    int a = 10;
    int b = 20;
      
    auto func = [=](type i)->int {
        switch (i)
        {
            case add:
                return a + b;
            case sub:
                return a - b;
            case mul:
                return a * b;
            case divi:
                return a / b;
        }
    };
      
    cout<<func(add)<<endl;
}

 

显而易见的效果,代码简单了,你也少写了一些代码,也去试一试C++中的Lambda表达式吧。

关于Lambda那些奇葩的东西

看以下一段代码:

复制代码代码如下:


#include<iostream>         
using namespace std;       
                           
int main()                 
{                          
    int j = 10;            
    auto by_val_lambda = [=]{ return j + 1; };
    auto by_ref_lambda = [&]{ return j + 1; };
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
                           
    ++j;                   
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
                           
    return 0;              
}

 

程序输出结果如下:

复制代码代码如下:


by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12


你想到了么???那这又是为什么呢?为什么第三个输出不是12呢?

 

在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。

再来一段更晕的代码:

 

复制代码代码如下:


#include<iostream>                  
using namespace std;                
                                    
int main()                          
{                                   
    int val = 0;                                    
    // auto const_val_lambda = [=](){ val = 3; }; wrong!!!
                                    
    auto mutable_val_lambda = [=]() mutable{ val = 3; };
    mutable_val_lambda();           
    cout<<val<<endl; // 0
                                    
    auto const_ref_lambda = [&]() { val = 4; };
    const_ref_lambda();             
    cout<<val<<endl; // 4
                                    
    auto mutable_ref_lambda = [&]() mutable{ val = 5; };
    mutable_ref_lambda();           
    cout<<val<<endl; // 5
                                    
    return 0;      
}

 

这段代码主要是用来理解Lambda表达式中的mutable关键字的。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值。例如上面的Lambda表达式可以看成以下仿函数代码:

 

复制代码代码如下:


class const_val_lambda
{
public:
    const_val_lambda(int v) : val(v) {}
    void operator()() const { val = 3; } // 常量成员函数
 
private:
    int val;
};

 

对于const的成员函数,修改非静态的成员变量,所以就出错了。而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了。都是一些纠结的规则。慢慢理解吧。

总结

对于Lambda这种东西,有的人用的非常爽,而有的人看着都不爽。仁者见仁,智者见智。不管怎么样,作为程序员的你,都要会的。这篇文章就是用来弥补自己对C++ Lambda表达式的认知不足的过错,以免以后在别人的代码中看到了Lambda,还看不懂这种东西,那就丢大人了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。