最近学习cocos2d-x
的时候经常在触摸事件中看到lambda表达式
, 类似于swift
中的闭包和Objective-C
中的block
.
目录
好像好久都没有更新了, (~~强行~~)最近好忙呢【
以下程序使用clang编译, 采用C11标准, 如果读者和我一样使用clang手动编译, 注意加上
-stdlib=libc++
和-std=c++11
选项使用C11标准库
函数
lambda表达式其实就是从其他语言中的闭包借鉴来的, 本质上就是匿名的函数. 写程序肯定离不开是用函数和自己写函数. 函数把可以实现一定功能的代码封装到一起, 一方面可以增加代码的复用, 另一方面也可以是程序层次分明, 便于阅读. 为了调用函数, 在定义函数的时候都会定义函数名.
1
2
3
4
5
6
7
8
//定义函数名为"func_1"的函数
int func_1(int a) {
return a;
}
//调用函数
func_1(10);
return 0;
函数调用
除了使用函数名进行函数调用, 为了增加程序的灵活性和实现泛型, C++中也可以使用我们熟悉的函数指针
和function函数模板
来调用函数.
1
2
3
4
5
6
7
8
//使用函数指针调用"func_1"
int (*p)(int) = func_1;
(*p)(10);
//使用function模板调用"func_1"
function<int(int)> func;
func = func_1;
fun(10);
熟悉的sort函数
有时候函数写好之后就直接调用, 并且似乎只调用了一次就再也没使用过. 这种情况下, 不定义函数会显得程序结构混乱, 写了函数又感觉没什么必要. 最常见的场景就是sort函数, 基本上所有讲闭包的文章都会提sort函数.
sort
函数接受三个参数, begin
、end
分别是需要排序数组的头尾, compare
是一个返回值为bool compare(obj1, obj2)
的函数, 决定排序的方式(升序或降序, 以及如何比较两个元素大小). sort函数运行时在需要排序的数组中分别取出两个元素作为参数调用compare函数比较, 然后写回原数组.
1
2
3
4
5
6
7
8
9
10
//定义compare函数
bool compare(int num_1, int num_2) {
return num_1 < num_ 2;
}
int array[] = {2, 4, 1, 6};
//对array排序
sort(array, array + 3, compare);
//array = (1, 2, 4, 6)
sort函数这样写的确能够增加排序的方式, 不过compare函数与sort函数的调用是分离的, 阅读上会有些困难, 并且compare函数只使用了一次就不再使用. 在这种情况下, 我们就迫切需要一种定义和使用可以在一起, 但又不回过多影响阅读的结构.
lambda表达式
基于上述原因, lambda表达式出现了, 先看一下lambda表达式的格式
[捕获值](参数列表) -> 返回值 {函数体}
捕获值
lambda表达式可以直接使用上文定义的变量, 这个过程叫做捕获
, 同参数传递相同, 捕获分为值传递
和引用传递
, 也可以指定只捕获某几个变量.
使用应用传递时, 如果要更改外部变量, 需要在参数列表后加上mutable
关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int a = 10;
int b = 100;
//值传递使用a,b, 其实默认[]就是值传递
[=](int num) -> int {
a += 10;
b += 100;
return a + b + num;
};
//引用传递使用a,b
[&](int num)mutable -> int {
a += 10;
b +=100;
return a + b + num;
};
//值传递使用a, 引用传递使用b
[a, &b](int num)mutable -> int {
a += 10;
b += 100;
return a + b + num;
};
//只使用a, 引用传递
[&a](int num)mutable -> int {
a += 10;
return a + num;
};
//各个表达式调用结果就不用多说了吧
参数列表、返回值、函数体
和函数相同, 没什么可以多说的…
不过除了捕获值
和函数体
之外, 其他的部分都可以根据情况省略掉, 编译的时候会根据上下文推导出来.
lambda表达式的调用
直接调用
可以把lambda表达式整体看成是函数名, 后面加上参数就可以直接调用
1
[](int num) -> int {return num} (10);
像函数一样调用
之前也说明了, lambda表达式本质上是匿名函数, 自然能够用调用函数的方法去调用. 对于函数指针, 要求lambda表达式没有捕获外部变量;而对于function模板就无所谓了, 也可以使用auto自动推断.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int a = 10;
//函数指针调用
int (*p) = [=](int num) -> int {
return a + num;
}; //错误, 函数指针调用的函数不能直接使用外部变量
int (*p2) = [](int num) -> {
return num;
};
(*p_2)(10);//正确调用
//function模板调用
function<int(int)>func;
func = [=](int num) -> int {
return a + num;
};
func(10);
//auto自动判断lambda表达式类型
auto func_2 = [=](int num) -> int {
return a + num;
};
func_2(10);
再回到sort函数
知道了lambda表达式的使用之后就可以解决之前在sort函数中遇到的问题了
1
2
3
4
int array[] = {2, 4, 1, 6};
sort(array, array + 3, [](int num_1, int num_2) -> bool {
return num_1 < num_2;
});
是不是比刚才简洁不少, 阅读器来也不是那么困难→_→(如果想swift一样可以尾随闭包就更好了)
除了向sort函数或者各种交互事件等需要回调函数的场景, 我们在写函数的时候也可以试着使用lambda表达式, 比如利用lambda表达式传值之类的, 简化代码.