Cocos 2d-x 3.0 版本中引入了C++ 11的特性。其中就包含了回调函中使用Lambda对象。

下面我们来看一段TestCpp中的代码:

在上图的触摸事件的回调函数中,共使用了三次Lambda表达式:

[ ](Touch * touch,Event * event){ };

下面我们就来介绍一下Lambda表达式的使用方法。

正常情况下,如果我们需要在很多地方使用相同的操作,通常应该定义一个函数来实现这个功能。

而有些时候,我们只需要在一两个地方使用到一些简单的操作,而又不想去定义这个函数名,那么此时便可以Lambda表达式来实现我们的功能。

一个完整的lambda表达式的表达形式如下:

[capture list](parameter list)->return type (function body)

[捕获列表] (参数列表) ->返回类型 (函数体)


那么为什么图中的Lambda表达式的形式与上述的形式不一样呢?

原因是 Lambda表达式的参数列表和返回类型是和可以忽略的,但是捕获列表和函数体一定要包含。

也就是说,Lambda表达式实际上就是一个匿名函数,它的优点与内联函数(又称内嵌函数、内置函数)类似,但Lambda表达式可能会定义在函数内部。

那么内联函数的优点是什么呢?我们举个例子来说明,比如我们的程序中有这样一段代码:

void A(){

....//函数体略

}

void main(){

.... //省略

A( );//调用A函数

上述代码执行调用函数的主要过程如下:

1.主调函数main执行完调用A函数前的语句后,在转去调用A函数前,首先需要记录当前执行的指令地址,也就是做一个“保护现场”的操作,用于执行完A函数后继续执行后续代码。

2.然后流程的控制会被转移到A函数的入口,并且执行A函数中的函数体内的语句.

3.执行完成后,流程才会返回到之前记录的地址处,并且根据之前所记录的信息做恢复现场操作,保证程序正常执行。

上述过程的每一个操作都需要花费一定的时间,如果A函数需要被频繁的使用,那么我们花费的时间就会很长,从而造成效率降低。

为了解决这个问题,C++为我们提供的了内联函数,所谓内联函数,就是通过将一个函数声明为inline function,从而达到在编译的过程中,直接将所调用的函数的函数体部分直接拷贝到主调函数,而不需要将流程转到这个函数中去,以此来减少程序的运行时间。

这是因为当一个函数的函数体规模很小的时候,函数调用过程中的时间开销会超过执行函数所需要的时间。

这就是使用内联函数的好处,而对于Lambda表达式,我们可以将它理解为一个未命名的内联函数。

下面我们对lambda表达式的形式进行逐一分析:

1.“ [捕获列表] ”

首先我们观察一下上图中的第一个lambda表达式与第三个lambda表达式的捕获列表部分的区别。

可以看到,上图的第一个表达式中捕获列表为空 [ ],而第三个表达式中的捕获列表中包含了一个等号 [=]。

下面我们再观察一下上图中第一个与第三个lambda表达式的函数体内都使用到了哪些变量。

可以看到,第一个表达式中所有的变量,均是在Lambda表达式中定义的(log除外,因为log函数包含在头文件中),

而在第三个表达式中所使用到的sprite1,sprite2等变量,并不是在lambda表达式中定义的,而是当前函数中或是当前类中的变量。

那么我们就可以总结出,在Lambda表达式的函数体内,是不能够访问到外部的变量的,如果想要使用函数体外定义的变量,就需要将它们进行捕获,上图第三个lambda表达式采用的正是“值捕获”,与它对应的另外一种为“引用捕获”。

[ ]:空捕获列表,即lambda表达式不能够使用所在函数中的变量

[=]:值捕获,即lambda表达式可以以拷贝的方式访问到函数中变量的值

[&]:引用捕获,即lambda表达式中所使用的其所在函数中的变量均是引用方式

当我们不希望在捕获的时候将所有的变量都捕获的时候,我们可以使用如下的方式进行捕获,例如:

[=sprite1,&sprite2]

这里我们仅仅捕获了两个变量,第一个变量是以值拷贝的方式捕获,第二个是以引用方式捕获,变量与变量之间用逗号分隔。

正常情况下,如果一个变量是值拷贝,Lambda不能改变它的值,如果我们希望改变一个值拷贝的变量的值,就需要在参数列表前加上关键字mutable

例如:
auto s1=10;

auto s2=[=s1](){return ++s1};//错误,因为s1是值拷贝,不能改变s1的值

auto s2=[=s1]() mutable {return ++s1};//正确

2.(参数列表)

Lambda表达式传递参数时需要注意的是,Lambda表达式不能有默认参数,也就是说Lambda表达式的实参数与形参数必须相等。

其他情况Lambda表达式的参数部分与普通函数并无区别,一般会结合STL使用。

例如:

void test(){

vectormyVec; //创建一个int 类型容器

myVec.push_back(1); //插入数据 1

myVec.push_back(2);//插入数据 2

int a=10; //创建局部变量 a

for_each(myVec.begin(),myVec.end(),[&](int v)mutable(cout<<v+a<

cout<<a<

}

3.->return type

之间我们已经提到,Lambda的返回值是可以省略的。

原因是编译器会根据return的类型来推导返回值,但是如果需要return后再做一个类型转换,我们就可以通过写一个返回类型来完成。

例如:cout<<[](float f){return f}(1.5); //这里我们将1.5作为参数传入并打印,返回结果就是实参的值1.5

cout<<[](float f)->int{return f}(1.5); //我们将返回值强制转换为int 输出结果为1

4.函数体

函数体部分与普通函数并无区别,我们只需要注意以上几点,在函数体部分就不会出现问题。

现在再回头看看TestCpp中的触摸事件,我们就可以明白其中的道理了。

Cocos2d-x v3.0 lambda表达式的使用的更多相关文章

  1. ios – 如何从变量访问属性或方法?

    是否可以使用变量作为Swift中方法或属性的名称来访问方法或属性?在PHP中,您可以使用$object->{$variable}.例如编辑:这是我正在使用的实际代码:解决方法你可以做到,但不能使用“纯粹的”Swift.Swift的重点是防止这种危险的动态属性访问.你必须使用Cocoa的Key-ValueCoding功能:非常方便,它完全穿过你要穿过的字符串到属性名称的桥,但要注意:这里是龙.

  2. iOS &gt;&gt;块&gt;&gt;更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  3. ios – Xcode Bot:如何在post触发器脚本上获得.ipa路径?

    我正在使用机器人来存档iOS应用程序,我需要获取.ipa产品路径才能将其发布到我们的分发系统中.机器人设置:并使用脚本打印所有env变量,其中不包含ipa文件的路径.此外,一些变量指向不存在的目录,即:XCS_OUTPUT_DIR这里的env变量输出:除此之外,我还能够确认.ipa文件是在另一个文件夹中创建的(/IntegrationAssets//

  4. ios – 使用附加字符串本地化Info.plist变量

    我正在尝试本地化应用程序的名称,同时仍然能够根据构建配置追加字符串.所以目前它被设置为:该设置定义为:通过这种方式,我们可以为应用程序添加后缀以用于不同的beta版本.问题是,当我们尝试本地化本地化的InfoPlist.strings中的应用程序显示名称时,就像这样我们覆盖存储在Info.plist中的值,并丢失后缀字符.这有什么好办法吗?

  5. iOS – 开始iOS教程 – 变量之前的下划线?

    这是正确的还是我做错了什么?

  6. ios – 静态计算变量被多次实例化

    我有一个日期格式化程序,我试图在UITableViewCell子类中创建一个单例,所以我创建了一个这样的计算属性:问题是我不止一次看到print语句,这意味着它不止一次被创建.我已经找到了其他方法,但我很想知道这里发生了什么.有任何想法吗?解决方法您的代码段相当于只获取属性,基本上它与以下内容相同:如果你只想运行一次,你应该像定义一个惰性属性一样定义它:

  7. ios – UIApplication.delegate必须仅在主线程中使用[复制]

    我应该在主调度中的viewControllers中声明这些)变量位置声明定义了它的范围.您需要确定这些变量的范围.您可以将它们声明为项目或应用程序级别(全局),类级别或特定此功能级别.如果要在其他ViewControllers中使用这些变量,则使用公共/开放/内部访问控制将其声明为全局或类级别.

  8. ios – 无法理解Objective-C块文档

    为什么localVariable“按价值使用?”>如果我在第二个例子中将__block存储类型添加到localVariable,我错误地假设该块关闭了变量,所以它将它保留在堆中直到块被释放?解决方法Howexactlyisoneexample“accessedbyreference”whiletheotheroneisaccessedbyvariable?self是当前正在执行找到块的方法的对象.强引用只是意味着对象的保留计数增加.IfIaddthe__blockstoragetypetolocalVar

  9. ios – 为BOOL变量编写getter和setter

    显然,使用obj-c,通常没有理由编写getter和setter(感谢有用的mr@synthesize).所以现在,需要做到这一点,我遇到了一个我不知道如何编写它们的问题.:p我敢肯定我可能不会以正确的方式解决我的问题–只是将我的对象子类化得更容易–但我正在尝试编写类别代码以添加属性,因为(在开头)它更快,因为我想学习如何在我的应用程序中使用类别代码.我有这个:我在setter中没有if查询就试过

  10. ios – 为什么不保留__block变量(在非ARC环境中)?

    我正在阅读__blockvariables上的文档,并考虑我使用__block的情况.对我来说,似乎我需要两种情况:>在块中使用时将变量标记为读写>在块内引用self时避免保留周期从表面上看,这两件事似乎并不相关.我认为__block变量没有被保留为更多的技巧我需要记住避免保留周期的特定用例.我想知道,为什么不能保留它们是否有更重要的建筑理由?

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部