[iOS、Unity、Android] 淺談閉包的使用方法

前言


咱們常常所編程語言的的進步速度是落後於硬件的發展速度的。html

可是最近幾年,閉包語法在各個語言中都有本身的體現形式,例如java

  •  C語言中使用函數指針做爲回調函數的入口;ios

  •  Java和C#語言中的Lambda語法表達式;編程

  •  Objective-C語言中的Blocks語法;數組

  •  C#語言中的Delegates語法;閉包

  •  C++語言中的Functions對象;編程語言

歷史


Peter J. Landin 在1964年將術語 閉包 定義爲一種包含 環境成分 和 控制成分 的實體,用於在他的SECD 機器上對錶達式求值。Joel Moses 認爲是 Landin 發明了 閉包 這一術語,用來指代某些其開放綁定(自由變量)已經由其語法環境完成閉合(或者綁定)的 lambda 表達式,從而造成了 閉合的表達式,或稱閉包。
函數

 

使用方法


C++語言中的Functions對象:測試

C++11標準開始支持閉包,這是一種特殊的函數對象,由特殊的語言結構—— lambda表達式 自動構建。spa

C++閉包中保存了所有nonlocal變量的拷貝或引用。

若是是對外界環境中的對象的引用,且閉包執行時該外界環境的變量已經不存在(如在調用棧上已經unwinding),那麼可致使undefined behavior,由於C++並不擴展這些被引用的外界環境的變量的生命期。

常見代碼以下:

//
//  main.cpp
//  Interface
//
//  Created by lewis on 4/30/15.
//  Copyright (c) 2015 lewis. All rights reserved.
//

#include <iostream>
#include <string>
#include <vector>

using namespace std;

//構造string向量
vector<string> GetNameList()
{
    static vector<string> names;
    
    names.push_back("劉輝");
    names.push_back("李靜波");
    names.push_back("崔亞允");
    names.push_back("趙雅");
    names.push_back("管輝");
    names.push_back("白志剛");
    names.push_back("王斌");
    names.push_back("白雅靜");
    names.push_back("張浩");

    return names;
}

void foo(string myname) {
    vector<string> names = GetNameList();
    
    //經過遍歷string向量,使用閉包完成判斷條件
    vector<string>::iterator i = find_if(names.begin(), names.end(), [&](const string& s){
        
        //判斷操做值與參數相等是否相等
        return s == myname;
    });
    

    
    //輸出判斷獲得的結果
    cout  <<(string)(*i) << endl;
}

int main(int argc, const char * argv[]) {

    foo("劉輝");
    
    return 0;
}

一、聲明閉包變量

C++中閉包的聲明語法,要使用 function 類型來聲明變量,以下所示

 std::function<float(float)> colsure; 

其中,第一個 float 表明了閉包的返回值類型,第二個 float 表明了閉包的參數數據類型爲浮點型

二、賦值閉包變量

C++中閉包的賦值語法,要使用 [=] 或 [&] 符號開頭,以下所示

colsure = [=](float f) {
      f += 10.0f;
      return f;
};

 

其中, [=] 表明了咱們將要進行的閉包傳值是單向賦值

 [&] 在使用過程當中,常常做爲引用傳值使用,以下所示

std:function<float(float&)> col;
col = [&](float& f){
      f += 10.0f;
      return f;      
};

 三、使用閉包變量

使用 [=] 和 [&] 聲明而且賦值後的閉包變量,在使用結束後的結果以下

//聲明一個浮點型變量
float floatValue = 1.0f;
//聲明計算結果浮點型變量
float resultValue = 0.0f;

//使用[=]類型的閉包變量
resultValue = colsure(floatValue);
//輸入結果
std::cout<<floatValue<<":"<<resultValue<<endl;

//使用[&]類型的閉包變量
resultValue = col(floatValue);
std::cout<<floatValue<<":"<<resultValue<<endl;

經過打印的結果,

1.0:10.0
10.0:10.0

 

 [=] 和 [&] 分別表明了值傳遞和引用傳遞的兩種方式。

 

Objective-C中的Blocks變量:

Blocks語法支持的系統版本爲OS X 8或者更高版本,iOS 4或者更高版本.

常見的代碼以下:

//
//  main.m
//  BlockSample
//
//  Created by lewis on 4/30/15.
//  Copyright (c) 2015 lewis. All rights reserved.
//

#import <Foundation/Foundation.h>


NSArray *GetNameList()
{
    static NSMutableArray *names = nil;
    
    if (names == nil) {
        names = [[NSMutableArray alloc] init];
        [names addObject:@"劉輝"];
        [names addObject:@"崔亞允"];
        [names addObject:@"李靜波"];
        [names addObject:@"趙雅"];
        [names addObject:@"管輝"];
        [names addObject:@"王斌"];
        [names addObject:@"張浩"];
    }
    
    return names;
}

void foo(NSString *myname)
{
    //獲取到姓名列表
    NSArray *names = GetNameList();
    
    
    //經過遍歷數組對象,使用Block進行判斷
    NSInteger index = [names indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
        return [obj isEqualToString:myname];
    }];
    
    
    //輸出結果
    NSLog(@"%@",names[index]);
}


int main(int argc, const char * argv[])
{
    foo(@"崔亞允");
    return 0;
}

一、聲明Block語法變量

 float(^block)(float); 

咱們會發現,Blocks語法變量的聲明語法與函數指針變量的聲明語法 float(*pointer)(float); 很是相似,只是在運算符號上有區別;

二、賦值Block語法變量

block = ^ (float f){
        f += 10.0f;
        return f;
};

 在對Blocks變量進行賦值時,要注意全部的Block變量都是用 "^" 運算符號來開頭,而且有返回值類型的Block變量,在Block代碼塊內部的return 返回類型要相同。

詳細的Block語法參考:http://www.cnblogs.com/daxiaxiaohao/p/3913467.html

 

C#語言中的Lambda表達式:

Lambda表達式實在C#4中出現的語法糖,用來提升程序的開發效率,簡化Func類型變量和delegate對象的寫法。

常見的代碼以下:

using System;
using System.Collections.Generic;

namespace LambdaSample
{
	class MainClass
	{
		public static List<string> GetNameList()
		{
			List<string> names = new List<string> ();

			names.Add ("劉輝");
			names.Add ("崔亞允");
			names.Add ("李靜波");
			names.Add ("趙雅");
			names.Add ("管輝");
			names.Add ("白志剛");

			return names;
		}

		public static void foo(string myname)
		{
			//獲取姓名列表
			List<string> names = GetNameList ();

			//經過Lambda表達式做爲判斷條件進行查詢
			string result = names.Find ((x) => {
				return x == myname;
			});

			//輸入查詢結果
			Console.WriteLine(result);
		}

		public static void Main (string[] args)
		{
			//測試
			foo ("崔亞允");
		}
	}
}

一、聲明C#語言中的Lambda表達式變量

在C#語言中,能夠經過 Func 類型來聲明Lambda變量,以下所示:

Func<float,float> func;

或者使用 delegate 類型來聲明Lambda變量,以下所示:

//定義一個delegate類型Interface
delegate float Interface(float x);

public static void Main (string[] args)
{
     //使用Interface類型來聲明Lambda變量
     Inteface inter_func;    
}

 

二、賦值C#語言中的Lambda表達式變量

在C#語言中,使用 => goes to 運算符來生成變量,以下所示:

func = (x) => {
    x += 10.0f;
    return x;
};

  => goes to運算符的左邊是閉包類型的浮點型參數,右邊是閉包變量準備進行的邏輯運算,以 {} 包括。

三、使用C#語言中的Lambda表達式變量

和調用函數同樣,以下所示:

//聲明Func類型變量
Func<float,float> func;

//爲func賦值Lambda閉包
func = (x) => {
    x += 10.0f;
    return x;
};

float floatValue = 1.0f;
float resultValue = 0.0f;

//調用func變量,計算結果而且賦值給resultValue
resultValue = func (floatValue);

//進行輸出
Console.WriteLine (resultValue);

 

 

總結 


其實在計算機科學中,閉包Closure)是詞法閉包Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即便已經離開了創造它的環境也不例外。因此,有另外一種說法認爲閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時能夠有多個實例,不一樣的引用環境和相同的函數組合能夠產生不一樣的實例。

須要注意的一點是

閉包一詞常常和匿名函數混淆。這多是由於二者常常同時使用,可是它們是不一樣的概念!!!!

相關文章
相關標籤/搜索