首页 > 其他分享 >lambda表达式

lambda表达式

时间:2024-04-01 14:30:08浏览次数:18  
标签:函数 int price rate 捕捉 表达式 lambda

lambda表达式

c++98中的一个例子

在c++98中如果想要对一个数据集合中的元素进行排序。可以使用std::sort方法。

#include<algorithm>
#include<functional>

int main()
{
    int array[]={4,1,8,5,3,7,0,9,2,6};

    //默认按照小于比较,排出来的结果是升序的
    std::sort(array,array+sizeof(array)/sizeof(array[0]));

    //如果需要降序,需要改变元素的比较规则
    std::sort(array,array+sizeof(array)/sizeof(array[0]),greater<int>());
    return 0;
}

如果待排序元素为自定义类型,需要用户定义排序时的比较规则:

struct Goods
{
	string _name; // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price < gr._price;
	}
};

int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
	3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), ComparePriceLess());
}

随着C++语法的发展,人们开始觉得上面的写法太复杂了,每次为了实现一个algorithm算法,
都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,
这些都给编程者带来了极大的不便。因此,在C++11语法中出现了Lambda表达式。

lambda表达式

struct Goods
{
	string _name; // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠萝", 1.5, 4 } };

	//auto goodsPriceLess = [](const Goods& x, const Goods& y)->bool {return x._price < y._price; };
	auto goodsPriceLess = [](const Goods& x, const Goods& y) {return x._price < y._price; };
	cout << goodsPriceLess(v[0], v[1]) << endl;
	sort(v.begin(), v.end(), goodsPriceLess);
	return 0;
}

lambda表达式实际上是一个匿名函数。

lambda表达式语法

lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement
}

1. lambda表达式各部分说明
[capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来
判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda
函数使用。

(parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以
连同()一起省略。

mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量
。使用该修饰符时,参数列表不可省略(即使参数为空)。

->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回
值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推
导。

{statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。

有几点说明:例如下面这个场景,如果我们不想传值传参,但又想让rate为2.55,这时捕获列表就派上用场,直接使用值传递的方式捕捉变量rate。

int main()
{
	int x = 0, y = 2;
	double rate = 2.555;
    auto add3 = [rate](int x, int y) {return (x + y)* rate; };
	return 0;
}

如果我们碰到一个场景:我们想要交换两个变量,但是不想传值传参,该如何去完成呢。

auto swap=[](int x,int y){int tmp=x;x=y;y=tmp;};

我们可能会想到上面所说的mutable,可是尝试过后发现x和y的值并没有交换,这是因为mutable让捕捉的x和y可以改变,但是他们依旧是外面x和y的拷贝。

int x = 0, y = 2;
auto swap1 = [x, y]() mutable {

	int tmp = x;
	x = y;
	y = tmp;
};
swap1();

我们用引用的方式捕捉即可以完成上述功能。

auto swap2 = [&x, &y](){
	int tmp = x;
	x = y;
	y = tmp;
};
swap2();

捕获列表的说明

捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。              (父作用域指包含lambda函数的语句块)
[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针

int a = 0;
int b = 1;
int c = 2;
int d = 3;
const int e = 1;
cout << &e << endl;

// 引用的方式捕捉所有对象,除了a
// a用传值的方式捕捉
auto func = [&, a] {
    //a++;  a的值无法改变
	b++;
	c++;
	d++;
	//e++;  e的值无法改变
	cout << &e << endl;
};

func();

我们从上述例子知道:语法上捕捉列表可以由多个捕捉项组成,并且以逗号分割,比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量;[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量。并且我们由e的地址是相同这点可以得到e也可以被const 引用捕捉。

注意:捕捉列表不允许变量重复传递,否则会导致编译错误。例如:[=,a]: =已经以值传递方式捕捉了所有变量,捕捉a重复。

函数对象与lambda表达式

函数对象,又称为仿函数,即可以像函数一样使用的对象,就是在类中重载了operator()运算符的
类对象

下面我们来对函数指针,仿函数,匿名函数对象来进行一个比较。

函数指针------能不用就不用    void(* ptr)(int x)

仿函数------类     重载operator(),使对象可以像函数一样使用

lambda--------匿名函数对象       函数内部,直接定义使用

class Rate
{
public:
	Rate(double rate) : _rate(rate)
	{}

	double operator()(double money, int year)
	{
		return money * _rate * year;
	}

private:
	double _rate;
};

int main()
{
	// 函数对象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);

	// lambda
	auto r2 = [=](double monty, int year)->double {return monty * rate * year; };
	r2(10000, 2);

	return 0;
}

从使用方式上来看,函数对象与lambda表达式完全一样。

函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可
以直接将该变量捕获到。

实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如
果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

标签:函数,int,price,rate,捕捉,表达式,lambda
From: https://blog.csdn.net/weixin_67401681/article/details/134781385

相关文章

  • 11天【代码随想录算法训练营34期】 第五章 栈与队列part02(● 20. 有效的括号 ● 1047
    20.有效的括号classSolution:defisValid(self,s:str)->bool:stk=[]upper=["(","{","["]lower=[")","}","]"]dictionary={")":"(&qu......
  • C++Lambda表达式
    Lambda表达式0、介绍c++11新引入了lambda表达式,一般用于定义匿名函数,使得代码更加灵活简洁。lambda表达式与普通函数类似,也有参数列表、返回值类型和函数体,只是它的定义方式更加简介,并且可以在函数内部定义。通常,lambda用于封装传递给算法或异步方法的几行代码。1、Lambd......
  • 波兰表达式代码
    importjava.util.ArrayList;importjava.util.List;importjava.util.Stack;publicclassPolan{publicstaticvoidmain(String[]args){//先定义波兰表达式//(3+2)*5-4=》32+5*4—StringExpression="32+5*4—";//将后......
  • 2024/3/30 21点的lambda表达式
    packagecom.atguigu;interfaceMyInterface{intsum(inti,intj);}interfaceMyhaha{inthaha();}//检查注解,帮我们快速检查我们写的接口是否函数式接口@FunctionalInterfaceinterfaceMyhehe{inthehe(inti);}//1.自己写实现类classMyInetfaceI......
  • Java(2) ----- 异常、多线程、同步安全、死锁、并发包、Lambda表达式、Stream流
    异常方法默认都可以自动抛出运行时异常!自定义异常:(1)自定义编译时异常1、定义一个异常类继承Exception2、重写构造器3、在出现异常的地方用thrownew自定义对象抛出4、编译时异常是编译阶段就报错,提醒跟家强烈,一定需要处理!(2)自定义运行时异常1、定义一个异常类继承RunTimeE......
  • C++U6-10 - 表达式与表达式求值
    学习目标 算数表达式 三种算数表达式 中缀转后缀  计算机的转换逻辑 中缀转后缀 【算法分析】从左到右进行遍历。1.遇到的是运算数,直接输出。2.遇到的是左括号'(',直接压入堆栈(括号是最高优先级,无需比较;入栈后优先级降到最低,确保其他符号正常入栈)。......
  • linux正则表达式之*
    1.*含义linux正则表达式*表示重复0个或多个前一个重复字符2.样例正则表达式*样例命令:grep-n"min*"anaconda-ks.cfg#找出含有mi、min、minn等字符串的行。注:因为*可以是0个,所以mi也是符合搜索字符串,另外,因为*为重复前一个字符的符号,因此,在*之前必须要紧挨着一个重复字......
  • 语法回顾-《Verilog编程艺术》之表达式
    目录表达式操作符操作符优先级整数算数操作符比较操作符逻辑操作符位运算操作符归约操作符移位操作符条件操作符连接操作符操作数向量的抽取数组的访问字符串表达式位长符号表达式赋值和截断与x/z比较参考《Verilog 编程艺术》魏家明著表达式表达式是......
  • 正则表达式
    正则表达式正表达式分类:正则表达式:REGEXP,REGularEXPression。正则表达式分为两类:BasicREGEXP(基本正则表达式)ExtendedREGEXP(扩展正则表达式)正则表达式定义:正则表达式(RegularExpression,通常简写为regex、regexp或RE)是一种文本模式,用于描述和匹配一系列符合某个......
  • springcloudgatewayRCE(spEl表达式)
    CVE-2022-22947SpringCloudGatewayRemoteCodeExecute漏洞/SpELCodeInjection漏洞基本介绍cloud全家桶网关作用l智能路由l负载均衡l协议转换l权限校验l限流熔断l黑白名单lAPI监控l日志审计SpringCloutGateway使用<dependency><groupId>org.......