初识Lambda表达式(匿名函数)

0.问题导向

使用C++ STL实现订单按照创建时间从小到大排查。

using Order = struct tagOrder{
    unsigned int createTimspec;//创建时间戳
    int id;                    //订单号
    int totalPrice;           //总价
    int status;               //订单状态
    int payType;              //支付类型
};
void orderSortByTime(vector<Order>& orders)
{
    sort(orders.begin(),orders.end());
}

这样使用算法库的sort函数,编译报错:

error: no match for ‘operator<’ (operand types are ‘tagOrder’ and ‘tagOrder’)
 43 | return *__it1 < *__it2; }.

编译器只默认支持对基本数据类型的大小比较,例如int,long等。自定义数据结构需要自定义比较函数。

using Order = struct tagOrder{
    unsigned int createTimspec;//创建时间戳
    int id;                    //订单号
    int totalPrice;           //总价
    int status;               //订单状态
    int payType;              //支付类型
};
int compare(Order a,Order b)
{
    return a.createTimspec<b.createTimspec;
}
void orderSortByTime(vector<Order>& orders)
{
    sort(orders.begin(),orders.end(),compare);
}

你发现没有,这个自定义的函数compare很简单,只有一行代码。但是每次调用仍然有函数调用的开销,如果系统中有大量的调用需求,那么函数调用对性能的影响就不能忽视了。

using Order = struct tagOrder{
    unsigned int createTimspec;//创建时间戳
    int id;                    //订单号
    int totalPrice;           //总价
    int status;               //订单状态
    int payType;              //支付类型
};
void orderSortByTime(vector<Order>& orders)
{
    sort(orders.begin(),orders.end(),[](Order a,Order b){return a.createTimspec<b.createTimspec;});
}

按照上图方法也可以实现订单排序功能,sort函数的第三个参数替代了自定义的compare函数,"[](Order a,Order b){return a.createTimspec<b.createTimspec;}",这串就是我们今天要学习的Lambda表达式

1.Lambda表达式简介

Lambda表达式,也称为Lambada函数,实际是一个匿名函数(不需要定义函数名),主要的使用场景是函数入参,例如算法函数和异步函数。在C++中,从C++11开始引入Lambda表达式,之后在后面的C++14、C++17、C++20、C++23版本对Lambda表达式都有更新和扩展。这里我们选择最初的C++11版本,学习下Lambda表达式的基本语法和用法。

2.Lambda表达式语法

Lambda基本语法如下,包含捕获、参数、修饰符、返回类型和实体五部分。其中,修饰符和返回类型是可选部分。下面结合例子学习这五部分组成。
[capture](parameters) modifiers -> return-type {body}

3.Captures

1>捕获引用类型和值类型

int arg=10;
auto lambdaCap = [&arg] (){arg++;};//capture by reference
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=11
return 0;

上图是捕获引用类型,不用解释。

int arg=10;
auto lambdaCap = [arg](){arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;
//编译失败
main.cpp:265:30: error: increment of read-only variable ‘arg’

上图编译失败。

int arg=10;
auto lambdaCap = [arg]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=10

增加mutable修饰符后编译通过,修饰符后面介绍。

2>捕获有效范围内的所有变量

 int arg=10;
 auto lambdaCap = [=]()mutable{arg++;};//capture by value
 lambdaCap();
 cout<<"arg="<<arg<<endl;//arg=10

上图是使用'='表示以值类型的方式捕获有效范围内的所有变量。

 int arg=10;
 auto lambdaCap = [&]()mutable{arg++;};//capture by value
 lambdaCap();
 cout<<"arg="<<arg<<endl;//arg=11

上图是使用'&'表示以引用的方式捕获有效范围内的所有变量。

4.Parameters

 auto lambdaAdd = [](int a,int b){return a+b;};
 cout<<"sum="<<lambdaAdd(1,2)<<endl;//sum=3

这里的参数和函数的入参类似,入参也可以有默认值。

 auto lambdaAdd = [](int a,int b=1){return a+b;};//capture by value
 cout<<"sum="<<lambdaAdd(1)<<endl;//sum=2

5.Body

实体部分类似普通函数的函数体,例如开端的订单排序例子中的Body返回创建时间的大小。

void orderSortByTime(vector<Order>& orders)
{
sort(orders.begin(),orders.end(),[](Order a,Order b){return a.createTimspec<b.createTimspec;});
}

6.Modifiers

可选部分,可以通过修饰符设置Lambda匿名函数的属性,例如在Captures部分我们用的mutable修饰符。还有noexcept、noreturn等。

int arg=10;
auto lambdaCap = [arg]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=10

7.Return-Type

可选部分,如果不设置返回类型,则由编译器根据代码逻辑自动判断类型,例如上面的所有例子都是这样。如果设置返回类型,则强制要求编译器按照该类型返回。

auto lambdaAdd = [](int a,int b)->long{return (long)a+b;};
cout<<"sum="<<lambdaAdd(0x7FFFFFFF,0x1)<<endl;//sum=2147483648

8.总结

这里只是简单介绍了Lambda函数的产生以及基本的语法和使用场景,还有很多深奥的相关部分需要持续学习。日拱一卒无有尽,终不唐捐入海流。

posted @ 2024-09-15 19:58  MadAdam  阅读(40)  评论(0)    收藏  举报