二者的定义:
Block :
^ return type (parameter list) {function body}
其中,返回类型的参数表时可以省略的,即最简略的方式:
^ {function body}
Lambda :
[capture list] (parameter list) -> return type {function body}
其中,返回类型和参数表也是可以省略的:
[capture list] {function body}
捕获(截获)变量
二者的定义出了使用的运算符不同之外, Lambda 还比 Block 多了一个 "capture list",即捕获列表,其实 Block 中也有对变量的捕获:
Block 中的捕获:如果要想在 Block 中截获一个变量,可以直接使用这个变量,但是此时使用的仅是这个变量的拷贝值,如果要在 Block 中修改这个变量,需要在变量之前使用
__block
来修饰。
Lambda 中的捕获:Lambda 捕获变量只针对于局部非 static 变量,如果要使用 static 变量或者使用定义在当前作用域的父级作用域的变量时,可以直接使用。要在 Lambda 中捕获的变量需在捕获列表里声明。并且,捕获分为“值捕获”和“引用捕获”,如果变量名为 value,
那么值捕获为:
[value]{}
引用捕获为:
[&value]{}
隐式捕获可以让编译器自动推断 Lambda 中要捕获的变量,隐式的值捕获:
[=]{}
隐式的引用捕获:
[&]{}
返回值
Block 的返回类型是可以省略的,而在 《C++ Primer》 中,关于 Lambda 的返回类型是这样说的:如果 Lambda 中含有除了 return 语句之外的其它语句,那么返回类型不可省略,但是实际测试下也是可以省略的,这个应该和编译器有关。
其它
Block “这是个位于 C 层面的特性,因此,只要有支持此特性的编译器,以及能执行块的运行期组件,就可以在 C、C++、Objective-C 、Objective-C++ 代码中使用它”(Effective Objective-C 2.0 第 149 页)
实际测试确实是这样,以下是一个简单的 CPP 程序:
int main(int argc, const char * argv[]) {
auto testLambda = [](int a , int b){
if (a > b){
return a;
}
else {
return b;
}
};
auto testBlock = ^(int a, int b){
return (a > b) ? a : b;
};
std::cout << testLambda(5, 9) << std::endl;
std::cout << testBlock(5, 9) << std::endl;
return 0;
}
我们在 CPP 中同时使用了 Lambda 和 Block ,二者都打印了 9 。同时,还看到 Lambda 中含有除了 return 之外的其它语句而没有声明返回类型。