从C++转到Java开发的这几年里,时常感慨Java里没有C++里的函数对象等好用的特性。最近安装了VS2012 Express尝鲜,偶然试了下Lambda,真是不得不惊呼“C++也能这样了!Java何时能支持原生函数对象啊!“,同时吐出几百两血,再想想悲剧的Java模板,再吐出几百两血。 😀
下面就用几个简单的例子说明一下。
一个例子
1 2 3 |
auto x = [] (int a) { return 2 * a; }; cout << x(2) << endl; // 4 |
一个简单例子,很简洁的语法,就可以写出一个lambda表达式,可以赋值给auto变量或function变量。 同时发现在VS2012 Express的IDE已经对这些特性支持的非常好,自动补全也非常给力。
例子中x的类型就是function<int(int)>。
Lambda的基本语法
- Lambda introducer或Capture Clauser
- Parameter list 声名lambda参数表的
- Mutable specification
- Exception specification 声名异常
- Return type clause 返回值
- Lambda body 函数体
其实除了第一项和第三项,其他的部分和写个函数很像。这里就主要讲讲1、3项。
首先一个Lambda表达式可以访问所有上下文中的变量(在一个{}之内的)。Capture Clauser就是用来指定Lambda Body是按值类型访问还是引用类型访问。
举个例子:
1 2 3 4 5 6 7 8 9 |
int a = 1; int b = 2; [a, &b] { // access a by value, access b by reference. cout << a << endl; b = 3; } // a is still 1. // b is 3 now. |
如果所有变量都想以值方式访问,可以用[=];都想以引用方式访问可以用[&]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
int a; int b; [=] { // 等价于[a,b] ... } [&] { // 等价于[&a, &b] ... } int c; // 如果只想c以引用方式访问 [=, &c] { // 那么就只有c是以引用方式访问 ... } |
前面的例子也说明,如果没有参数表,可以省略。
mutable关键字是和by value的访问方式有关。当我们以by value方式访问变量时,默认是不能对变量进行赋值的。但当我们声明为mutable的lambda时,就可以了。注意,这里修改的也仅仅是一个拷贝而不是值本身。
1 2 3 4 5 6 7 8 9 10 11 |
int a = 1; [=] { a = 2; // compiling error! } [=] () mutable { // parameter list can't be omitted. a = 2; // compile pass! } cout << a << endl; // still a == 1 |
和STL算法联用
1 2 3 4 |
vector<int> vec(10); generate_n(vec.begin(), 10, rand()); for_each(vec.begin(), vec.end(), [] (int a) { cout << a << endl; }); |
Lambda的加入方便了C++写出简洁的代码,可以和STL里很多算法联用,非常方便,功能强大。当然也不仅限于VS2012,新版的LLVM和GCC对lambda也支持的很好!
Java 8里会有这些吗?Who knows?