常用编程语言对Lambda表达式的支持(一)

2014-11-24 03:13:52 · 作者: · 浏览: 2

Lambda表达式,也称为匿名函数,是一种无需定义名称的函数或子程序,在很多高级语言中普遍存在。1958年LISP首先采用匿名函数,发展至今,越来越多的编程语言开始支持该特性,包括C++, PHP等,本文列举了常用的编程语言对lambda表达式的支持,增强对lambda表达式的认识,并了解不同是如何支持lambda表达式的。

Java 8

2013年Java 8的发布,宣布java对lambda表达式的支持,在java支持lambda表达式之前,我们必须这样写代码:

button.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
        ui.dazzle(e.getModifiers());
    }
});

你还需要导入java.awt.event.ActionListener功能接口。而java8带来了lambda表达式,我们只需这样写:

button.addActionListener(e -> { ui.dazzle(e.getModifiers()); });

编译器知道lambda表达式符合void actionPerformed(ActionEvent)方法的定义,看起来lambda实体返回的是void,实际上编译器能推断出参数e的类型就是java.awt.event.ActionEvent。

java 8的lambda表达式的出现主要是大大简化了功能接口的编写,同时java8还提供了java.util.functions包,包含了很多新的功能接口和迭代方法,这些功能都分成类似于LINQ。

C++ 11

c++ 11也开始支持labmda表达式来,C++ 11的lambda表达式的格式如下:

[capture](parameters) mutable or exception->return-type {body} 

[capture]表示一个Lambda表达式的开始,这部分是必须的,不能省略。capture是传递给编译器自动生成的函数对象类的构造函数,capture只能使用那些定义当前lambda表达式之前所定义的,并且在lambda作用范围内可见的局部变量(包含lambda所在类的this),包含以下形式:

空, 不使用该参数;=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。this。函数体内可以使用Lambda所在类中的成员变量。a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。&a。将a按引用进行传递。a, &b。将a按值进行传递,b按引用进行传递。=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

parameters表示重载的()操作符参数,没有参数时,可以省略。参数可以按值(如:(a, b)),也可以按引用(如:(&a, &b))传递参数。

mutalbe或exception声明可以省略,按值传递[capture]参数时,加上mutalbe修饰符,可以修改参数拷贝的值(修改的是值类型的拷贝)。exception声明用于指定函数抛出的异常,如抛出整数类型的异常:throw(int)。

“-> return-type”,表示函数返回值类型,当没有返回值时,或者函数体内只有一处return语句(编译器可以推断出返回值的类型),该部分就可以省略。

{body}表示函数的实现,函数体可以空,当花括号不能省略。

看一个例子,该例子是统计字符串中的大写字母,使用for_each遍历字符串,使用lambda表达式检查字母是否为大写,如果是大学,uppercase加1:

int main()
{
    char s[]="Hello World!";
    int uppercase = 0; //modified by the lambda
    for_each(s, s+sizeof(s), [&uppercase] (char c) {
        if (isupper(c))
             uppercase++;
    });
    cout<< Uppercase<<" uppercase letters in: "<< s<

uppercase是定义在lambda表达式外的一个变量,并且声明在lambda表达式之前,[&uppercase]中的“&”表示lambda函数体中使用的uppercase为一个应用类型,以便更新大写字母的个数。

Objective-C

下面的例子,分别是Objective-C和C++ 11的Lambda表达式写法:

^{ printf("Hello, World!\n"); } ();
[] { cout << "Hello, World" << endl; } ();

在创建Objective-C的lambda表达式时,在语法上是以“^”开始,而C++ 11是以“[]”开始。

实际上Objective-C的lambda表达式是构建在C语言之上的,也称为block,是C语言的扩展特性,如果你理解C语言的函数指针,那么有很容易理解Objective-C的block了,只是语法稍微不同。如下一个block的原型:

int (^maxBlk)(int , int);

除了“^”外,是不是和C语言的函数指针的声明一样。上面的示例就是声明一个block原型,名字为maxBlk,带有两个个int参数,返回值为int类型。

Objective-C有了Lambda表达式后,就可以很容易的定义一个满足maxBlk签名的函数,并且这个函数是匿名的。如下:

maxBlk = ^(int m, int n){ return m > n   m : n; };

你也可以这样写:

int (^maxBlk)(int , int) = ^(int m, int n){ return m > n   m : n; };

看如下Objective-C的代码,包含了3给block:

#import 
int (^maxBlk)(int , int) = ^(int m, int n){ return m > n   m : n; };

int main(int argc, const char * argv[])
{
    ^{ printf("Hello, World!\n"); } ();

    int i = 1024;
    void (^blk)(void) = ^{ printf("%d\n", i); };
    blk();
    return 0;
}

C#

C#早在2.0版本就引入了匿名方法,简化了我们编写事件处理函数的工作,使我们不再需要单独声明一个函数来绑定事件,只需要delegate关键字就可以编写事件处理代码了。如下:

// Create a handler for a click event
button1.Click += delegate(System.Object o, System.EventArgs e) {
    System.Windows.Forms.MessageBox.Show("Click!"); 
};

而C#3.0再更进一步地推出了Lamb