[置顶] 【amazing cocos2d-x 3.0之四】新触摸机制的前奏——Lambda

在介绍3.0新的触摸机制之前,我们有必要先介绍一下3.0新引进的C++ 11的Lambda表达式。

1. Lambda表达式

首先,什么是Lambda表达式呢?

Lambda表达式是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的Lambda抽象,是一个匿名函数,即没有函数名的函数。相信有数学背景的孩子,现在是不是感觉到Lambda这个读音很耳熟呢?嘿嘿

基本语法如下:

[捕获列表](形参列表) mutable->返回值类型 复合语句

其中除了“[]”(其中捕获列表可以为空)和“复合语句”(相当于具名函数定义的函数体),其它都是可选的。它的类型是唯一的具有成员operator()的非联合的类类型,称为闭包类型(closure type)。


例如调用<algorithm>中的std::sort,ISO C++ 98 的写法是要先写一个compare函数:

bool compare(int&a, int&b)
{
   return a>b; //降序排序
}
然后,再这样调用:

sort(a, a+n, compare);
然而,用ISO C++ 11 标准新增的Lambda表达式,可以这么写:

sort(a, a+n, [](int a, int b){return a>b;}); //降序排序
现在,是不是觉得代码简洁了很多呢?

由于Lambda的类型是唯一的,不能通过类型名来显式声明对应的对象,但可以利用auto关键字和类型推导:

auto f=[](int a, int b){return a>b;};
和其它语言的一个较明显的区别是Lambda和C++的类型系统结合使用,如:

auto f=[=](int a, int b){ return a>x;});//x被捕获复制
int x=0, y=1;
auto g=[&](int x){return ++y;});//y被捕获引用,调用g后会修改y,需要注意y的生存期
bool (*fp)(int,int)=[](int a,int b){return a>b;});//不捕获时才可转换为函数指针
Lambda表达式可以嵌套使用。

2. 在cocos2d-x 3.0中使用Lambda

例如创建一个MenuItem,如果不使用Lambda,需要为这个item写一个回调函数,代码如下:

	auto closeItem=MenuItemImage::create(
		"CloseNormal.png",
		"CloseSelected.png",
		CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));

void HelloWorld::menuCloseCallback(Object* sender)
{
    Director::getInstance()->end();
}

如果使用Lambda后,代码如下:

	auto closeItem=MenuItemImage::create(
		"CloseNoraml.png",
		"CloseSeleceted.png",
		[](Object* pSender)
	{
		Director::getInstance()->end(); //直接在这边添加代码
	});

是不是瞬间感觉到代码简洁了呢?这里还有另外一种写法,就是将回调的代码取出来,这样有一个好处就是可以多处调用callEnd。

	auto callEnd=[](Object* pSender)
	{
		Director::getInstance()->end(); //这里直接添加代码
	};

	auto closeItem=MenuItemImage::create("CloseNormal.png","CloseSelected.png",callEnd);

另外需要说的是:在默认情况下,即捕获字段为[]时,lambda表达式是不能访问外部变量的,即表达式的函数体内无法访问当前作用域下的变量。

如果要设定表达式能够访问外部变量,可以在[]内写入&或者=加上变量名,其中&表示按引用访问,=表示按值访问,变量之间用逗号分隔,比如[=number, &name]表示按值访问变量number,而按引用访问name。

用&引用来举个例子:假设点击按钮后,我要创建一个精灵。修改callEnd:

auto callEnd=[](Object* pSender)
{
    auto sprite=Sprite::create("Hello.png");
    sprite->setPosition(Point(50,50));
    this->addChild(sprite,5); //这里会报错
}

上面这种写法是错误的,因为表达式无法访问当前作用域的变量。修改代码如下:

auto callEnd=[&](Object* pSender)
{
    auto sprite=Sprite::create("Hello.png");
    sprite->setPosition(Point(50,50));
    this->addChild(sprite,5); //正常运行
}

---------参考自百度百科和天涯海阁












你可能感兴趣的:(lambda,cocos2d-x3.0,触摸机制)