常用編程語言對Lambda表達式的支持

jopen 10年前發布 | 22K 次閱讀 Lambda

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),包含以下形式:

  1. 空, 不使用該參數;
  2. =。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是值傳遞方式(相當于編譯器自動為我們按值傳遞了所有局部變量)。
  3. &。函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是引用傳遞方式(相當于編譯器自動為我們按引用傳遞了所有局部變量)。
  4. this。函數體內可以使用Lambda所在類中的成員變量。
  5. a。將a按值進行傳遞。按值進行傳遞時,函數體內不能修改傳遞進來的a的拷貝,因為默認情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
  6. &a。將a按引用進行傳遞。
  7. a, &b。將a按值進行傳遞,b按引用進行傳遞。
  8. =,&a, &b。除a和b按引用進行傳遞外,其他參數都按值進行傳遞。
  9. &, 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再更進一步地推出了Lambda表達式,使得編寫事件處理函數更加簡潔,lambda表達式更新一個計算表達式,使用“=>”符合來連接事件參數和事件處理代碼。如:

button1.Click += (o, e) => { System.Windows.Forms.MessageBox.Show("Click!"); };

在C#中,事件處理函數其實就是委托。委托除了可以作為事件處理函數,還可以作為函數指針,或回調函數使用,都可以使用lambda表達式的寫法。如:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

或者:

Func myFunc = x => x == 5;
bool result = myFunc(4); // returns false of cour

另外Lambda表達式在LINQ中發揮了重要作用。

PHP 5.3

PHP5.3增加了Lambda的支持,對于接受回調函數的PHP函數來說,lambda表達式非常方便。比如使用array_map函數遍歷數組,并將回調結果重新賦值給數字各元素。在早期PHP版本中,我們在調用array_map之前,必須事先定義好回調函數,比如:

function quoteWords()
{
     if (!function_exists ('quoteWordsHelper')) {
         function quoteWordsHelper($string) {
             return preg_replace('/(\w)/','"$1"',$string);
         }
      }
      return array_map('quoteWordsHelper', $text);
}

現在PHP5.3對lambda表達式的支持,使得編碼根據簡單。如下使用lambda表達式的實現:

function quoteWords()
{
     return array_map('quoteWordsHelper',
            function ($string) {
                return preg_replace('/(\w)/','"$1"',$string);
            });
}

Python

Python世界的lambda表達式根據簡單,只是在python世界里,lambda表達式主要適用比較小的函數。如普通Python的函數定義:

def func(x):
    return x * 2
func(2) # 4

使用lambda表達式的寫法:

func = lambda x:x*2
func(2) # 4

python的lambda表達式常用在一些回調中,比如:

a = [1, 2, 3, 4]
map(lambda x:x**2, a) # output: [1, 4, 9, 16]

或者

a = [1,2,3,4,5,6,7,8,9]
low, high = 3, 7
filter(lambda x:high>x>low, a) # output: [4,5,6]

"x**2"表示x的平方。"high>x>low"等于“high>x and x > low”。

Javascript

javascript中的lambda表達式通常稱為匿名函數,如果你使用過jquery庫,那么你肯定知道匿名函數,這里主要作為回調函數使用。比如:

$('#submit').on('click', function(){ functionbody. })

其中方法on的第二個參數就是匿名函數,javascript中的你們函數還有其他存在形式,比如:

var func = new Function('x', 'return 2*x;');

或者

var func = function(x) { return 2*x; }

還有就是很多js庫常用的方式,表示創建匿名函數,并調用之:

(function(x, y) {
    alert(x+y);
})(2, 3);

總結

lambda表達式的出現簡化了編碼量,多用于函數回調、事件、匿名函數,并且與閉包的結合使用,更能發揮強大的作用。另外,支持lambda表達式的編程語言有很多,這里主要介紹了我相對熟悉的幾種。

出處:http://guangboo.org/2014/01/16/lambda-supported-programming-language

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!