淺析匿名函數、lambda表達式、閉包(closure)區別與作用


淺析匿名函數、lambda表達式、閉包(closure)區別與作用

  所有的主流編程語言都對函數式編程有支持,比如c++11、python和java中有lambda表達式、lua和JavaScript中有閉包(closure)、ObjectC中有塊(blocks,^)。那么這幾個概念有什么共性和區別呢,只用普通函數不行嗎,為什么要創造這些炫酷的概念呢?

  一.匿名函數、lambda、closure區別

  從功能性上說lambda和closure(或是OC中的blocks)是一個東西,只是不同語言的不同稱呼罷了,它們都是匿名函數。若匿名函數捕獲了一個外部變量,那么它就是一個closure。

  二.匿名函數、lambda、closure作用

  簡單說,引入它們的作用有2個:

  • 簡潔
  • 捕獲變量

  首先說簡潔,匿名函數可以在其他函數內部聲明與定義,不用另外寫個命名函數,舉個栗子,顯示c++vector中每個值,若不使用匿名函數,代碼是這樣的

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 void show(int & value) {
 7     std::cout << "value " << value << std::endl;
 8 }
 9 
10 int main() {
11     vector<int> * v = new vector<int>(3, 1);
12 
13     for_each(v->begin(), v->end(), show);
14 
15     return 0;
16 }

若使用匿名函數是這樣的:

 1 #include <iostream>
 2 #include <vector>
 3 #include <functional>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 int main() {
 8     vector<int> * v = new vector<int>(3, 1);
 9 
10     for_each(v->begin(), v->end(), [](int & v){ 11 std::cout << "value " << v << std::endl; 12  });
13 
14     return 0;
15 }

  什么是捕獲變量呢?就是讓匿名函數可以使用匿名函數外定義的變量,但是匿名函數內的函數外變量是外部變量的一個clone(C++11可以捕獲引用,不是clone。OC中有__block,也可以直接改變外部變量的值),在匿名函數內修改(諾能)外部變量不會影響到外部變量。可以說closure就是函數+捕獲的變量。以lua為例:

 1 local intValue = 10;
 2 
 3 local func = function (p)
 4     intValue = intValue + p;
 5     return intValue;
 6 end
 7 
 8 print(func(3));
 9 print(func(3));
10 print(intValue)

打印的結果為:13,16,10。可見匿名函數的外部變量被捕獲到了func中。

三.匿名函數、lambda、closure在各個語言中的使用方式:

  1.ObjectC:

  在ObjectC中,匿名函數被稱為blocks(塊),即可以改變捕獲的原值、又可以捕獲克隆、但不能改變克隆值的值。捕獲並改變外部值,需要用__block,否則復制語句會報錯,使用代碼如下:

 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc, const char * argv[]) {
 4     @autoreleasepool {
 5         __block int foo = 10;
 6         
 7         int (^blockFunc)(int p) = ^(int p) {
 8             foo += p;
 9             return foo;
10         };
11         
12         NSLog(@"%d", blockFunc(4));
13         
14         NSLog(@"%d", foo);
15     }
16     return 0;
17 }  

  2.C++:

  C++中匿名函數被稱為lambda,即可以改變捕獲的原值、又可以捕獲克隆、又可以改變克隆值的值,語法形式可以簡單歸納如下:

  [capture](params)ops->ret{body;}

  capture是捕獲列表,params是參數表,opt是可選選項,ret是返回值類型,body是函數體。具體怎么使用可以參考C++11 lambda 表達式解析C++11 lambda 表達式

  3.lua:

  lua中的匿名函數被稱為閉包(closure),只能捕獲和改變原值的克隆,不能改變原值(table除外)

  4.python:

  python中的匿名函數被稱為lambda,只能捕獲克隆值,且不能改變他。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM