Lambda表达式起源于函数式编程语言,后来逐渐被面向对象的编程语言所采纳。本文所讨论的不是Lamda表达式的使用方法,而是通过对比Lamda表达式在C#和C++0x中的不同实现而找出其中的区别。
C#中Lamda表达式
基本的语法结构是()=>{}; 其中()是参数列表部分,用来定义函数的输入参数。定义参数时,用户并不需要定义参数的类型,编译器会根据函数体来“推演”参数的类型。=>部分读作goes to, 意思是函数有如下的函数体。{}部分便是函数的主体部分。一个求2个整数和的例子如下:
(a, b) => a + b;
当函数体只有一条语句的时候,{}符号和return关键字可以省略。
在Lambda函数体中,除了Lamda函数所定义的参数可以被使用外,Lamda函数体还可以使用外部变量,如下例:
void HostingFunction()
{
int c = 1;
Func<int, int, int> f = (a, b) => a + b + c;
}
注意被Lamda表达式所捕获的变量是与Lamda表达式是同步的,也就是说任何对原变量值的修改都会影响到Lamda表达式本身,即使对原变量值的修改发生在Lamda表达式生成之后。
C++0x中Lamda表达式
基本语法结构是[](){}; 其中[]是变量捕获列表,用来声明需要捕获的外部变量;()是参数列表部分,其功能等同于C# Lamda对应部分;{}是函数体部分,其功能等同于C#Lamda对应部分。一个简单的求2个整数和的例子如下:
[](int a, int b){ return a + b; };
可以看出,不同于C#的声明,C++0x Lamda表达式的参数列表中参数需要声明类型;函数体不能省略{}符号和return关键字;即使单条语句时也不能省略。
C++0x Lamda需要显式声明需要捕获的外部变量,如下例所示:
void HostingFunction()
{
int c = 1;
auto f = [c](int a, int b){ return a + b + c };
}
代码中声明了需要捕获外部变量c,则函数体中即可引用变量c,否则不能引用。不同于C# Lamda表达式,上述例子中对变量c的改变并不能影响f的行为,因为捕获的c是以值类型捕获的,也即是一份拷贝。如果对变量c采取按引用的方式捕获,则变量c的改变会影响f的行为。如下例:
void HostingFunction()
{
int c = 1;
auto f = [&c](int a, int b){ return a + b + c };
}
对比
通过对二者的简要对比可得如下几点结论:
- C# Lamda不需要变量捕获列表而C++0x Lamda则需要,所以C#捕获外部变量的方式更简洁。
- C++0x Lamda可以以按值或按引用两种方式来捕获变量,这是C++0x Lamda的最大优点;而C#只能以按引用的方式来捕获变量。
- C# Lamda的参数列表不需要定义类型;而C++0x则需要。C#通过类型推演来避免定义参数类型,这是一个非常吸引人的功能。
- C++ox 可以用auto关键字来声明Lamda;而C#则不能用var来声明Lamda
- 总的来讲,C# Lamda表达式更简洁优雅;而C++0x Lamda表达式则更功能强大。