当我第一听到这个概念的时候,第一反应想到的是离散数学中闭包的概念:若在一个集合上进行某种运算,其运算结果仍为集合中的元素,则称该集合为此运算上的闭包。
那么什么是编程语言中的闭包呢?我是一头雾水,网络达人有语:“外事不明问谷歌,内事不明问百度!”,英语向来差劲的在下,就先去找度娘商议了一番,度娘给出如下回答:
闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包”
一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境
(作用域)。在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和
Python,objective c 等语言中都能找到对闭包不同程度的支持。
度娘向来如此文艺,说的我是一知半解,到底神马意思呢?
我们还是举个例子来表达之:
-
/*************************************************************************
-
> File Name: lambda.cpp
-
> Author: dongdaoxiang
-
> Mail: dongdaoxiang@ncic.ac.cn
-
> Created Time: 2013年03月19日 星期二 11时31分42秒
-
************************************************************************/
-
-
#include<iostream>
-
#include<vector>
-
using namespace std;
-
int main()
-
{
-
int temp = 10;
-
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
-
vector::iterator it = ivec.begin();
while(it != ivec.end())
{
cout << *it << endl;
it++;
}
-
return 0;
-
}
我们要对于vector容器中的一系列元素进行处理,这里只是举个简单的例子就是遍历容器中的每一个元素,我们需要像上面的代码中那样,写一个循环然后加入我们处理的代码(这可能是我们一贯的思想),但是这样做存在两个问题:
1、代码的复用性不强,如果下次我们还要遍历另外的一个容器的时候,我们还要重复这里我们的工作。
2、这样写起来太繁琐。
这个时候,有人举手了!说我门可以使用c++的algorithm库内的函数来完成我们操作!于是乎就有了下面的代码:
-
/*************************************************************************
-
> File Name: lambda.cpp
-
> Author: dongdaoxiang
-
> Mail: dongdaoxiang@ncic.ac.cn
-
> Created Time: 2013年03月19日 星期二 11时31分42秒
-
************************************************************************/
-
-
#include<iostream>
-
#include<vector>
-
#include<algorithm>
-
using namespace std;
-
class printInt
-
{
-
public:
-
void operator()(const int x)
-
{
-
cout << x << endl;
-
}
-
};
-
-
int main()
-
{
-
int temp = 10;
-
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
-
std::for_each(ivec.begin(), ivec.end(), printInt());
-
return 0;
-
}
wow,看起来真的很酷,这样一来就把遍历的操作和输出的操作剥离开了,极大的增强了我们代码的复用性,从而简化了我们编程!假如,我们的需求仅仅是遍历并且输出容器中的每个元素的话,这可以说是一个完美的解决方案!但是我又有了这样的需求我不仅仅想要输出它,我还想对里面的元素进行排序,stl大侠又说了这不难看我的:
-
#include<iostream>
-
#include<vector>
-
#include<algorithm>
-
using namespace std;
-
class printInt
-
{
-
public:
-
void operator()(const int x)
-
{
-
cout << x << endl;
-
}
-
};
-
-
int main()
-
{
-
int temp = 10;
-
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
-
std::sort(ivec.begin(), ivec.end());
-
std::for_each(ivec.begin(), ivec.end(), printInt());
-
return 0;
-
}
wow,我大模板果然强大,碉堡了!碉堡了!高兴之余,新的需求又来了,我想要对容器中元素按照绝对值进行排序,而且这次不仅仅是排序了,我还想要让其中每一个元素加上一个局部的变量temp,没错这对于经常写代码的人来说,也不难实现,我们可以写一个绝对值排序的函数,如下:
-
#include<iostream>
-
#include<vector>
-
#include<algorithm>
-
using namespace std;
-
void abs_sort(vector<int> &ivec, int i, int j )
-
{
-
if(i < j)
-
{
-
int left = i;
-
int right = j;
-
int rawData = ivec[left];
-
int flag = abs(ivec[left]);
-
while(left < right)
-
{
-
while(left < right && abs(ivec[right]) > flag)
-
{
-
right--;
-
}
-
ivec[left] = ivec[right];
-
while(left < right && abs(ivec[left]) <= flag)
-
{
-
left++;
-
}
-
ivec[right] = ivec[left];
-
}
-
ivec[left] = rawData;
-
abs_sort(ivec, i, left - 1);
-
abs_sort(ivec, left + 1, j);
-
}
-
}
-
class printInt
-
{
-
public:
-
void operator()(const int x)
-
{
-
cout << x << endl;
-
}
-
};
-
-
int main()
-
{
-
int temp = 10;
-
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
-
//std::sort(ivec.begin(), ivec.end());
-
abs_sort(ivec, 0, ivec.size() - 1);
-
vector::iterator it = ivec.begin();
-
while(it != ivec.end())
{
-
*it += temp;
cout << *it << endl;
it++;
}
-
return 0;
-
}
恩,不错这样的确实现了我们需求,但是这里我们会发现我们又回到了第一个程序上面,将遍历和操作捆绑在了一起,而且需求我们自己手动写大量的代码,例如上面的abs_sort,这个放在以前好像的确没有什么更好的办法了,但是c11横空出世了,于是就有了下面的实现:
-
/*************************************************************************
-
> File Name: lambda.cpp
-
> Author: dongdaoxiang
-
> Mail: dongdaoxiang@ncic.ac.cn
-
> Created Time: 2013年03月19日 星期二 11时31分42秒
-
************************************************************************/
-
-
#include<iostream>
-
#include<vector>
-
#include<algorithm>
-
using namespace std;
-
-
int main()
-
{
-
int temp = 10;
-
vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
-
std::sort(ivec.begin(), ivec.end(), [](const int &x, const int &y) {return abs(x) < abs(y);});
-
std::for_each(ivec.begin(), ivec.end(), [&](int &x) { x += temp; cout << x << endl;});
-
return 0;
-
}
还等什么呢?撒花吧!颤抖吧!骚年们,这是c11的lambda带给我们的一个惊喜,这不仅仅是几行代码哦,这标志着c++也像Ruby、Python等时下流行的语言一样支持”闭包“了,虽然他有另外的一个名字:“lambda”!!让我们赶紧认识一个这个新朋友吧!
Lambda表达式是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数(译注:Lambda表达式也可以称为匿名函数,具有复杂行为的函数可以采用命名函数对象,当然,简单和复杂之间的划分依赖于编程人员的选择)。
上面的例子中参数 [](const int &x, const int &y) { return abs(x) < abs(y);
}是一个"lambda"(又称为"lambda函数"或者"lambda表达式"),
它描述了这样一个函数操作:接受两个整形参数a和b,然后返回对它们的绝对值进行"<"比较的结果。
[&] 是一个“捕捉列表(capture
list)”,用于描述将要被lambda函数以引用传参方式使用的局部变量。如果我们仅想“捕捉"参数v,则可以写为:
[&v]。而如果我们想以传值方式使用参数v,则可以写为:[=v]。如果什么都不捕捉,则为:[]。将所有的变量以引用传递方式使用时采用
[&], [=] 则相应地表示以传值方式使用所有变量。(译注:“所有变量”即指lambda表达式在被调用处,所能见到的所有局部变量)
这意味着什么,我们不用向以前c语言中的高阶函数那样,通过函数指针来传递函数的操作了,而指针的操作往往就是c/c++中99%的坑的来源!他可以在局部大函数里面访问环境中的局部变量,多么cool和powerful的功能!
为了描述一个lambda,你必须提供:
-
它的捕捉列表:它可以使用的变量列表(除了形参之外),如果存在的话("[&]" 在上面的记录比较例子中意味着“所有的局部变量都将按照引用的方式进行传递”)。如果不需要捕捉任何变量,则使用 []。
-
(可选的)它的所有参数及其类型(例如: (int a, int b) )。
-
组织成一个块的函数行为(例如:{ return v[a].name < v[b].name; })。
-
(可选的)采用了新的后缀返回类型符号的返回类型。但典型情况下,我们仅从return语句中去推断返回类型,如果没有返回任何值,则推断为void。
总结一下吧:本文简单的介绍了一下对于c11标准中新增的lambda表达的式的一些个看法,完全出自一家之言,如有不恰当的地方欢迎批评指正,如有雷同实属巧合!!
本文参考一下前辈的博文:
阅读(781) | 评论(0) | 转发(0) |