[iOS、Unity、Android] 浅谈闭包的使用方法

前言



我们经常所编程语言的的进步速度是落后于硬件的发展速度的。

但是最近几年,闭包语法在各个语言中都有自己的体现形式,例如

  •  C语言中使用函数指针作为回调函数的入口;

  •  Java和C#语言中的Lambda语法表达式;

  •  Objective-C语言中的Blocks语法;

  •  C#语言中的Delegates语法;

  •  C++语言中的Functions对象;

历史



Peter J. Landin 在1964年将术语 闭包 定义为一种包含 环境成分 和 控制成分 的实体,用于在他的SECD 机器上对表达式求值。Joel Moses 认为是 Landin 发明了 闭包 这一术语,用来指代某些其开放绑定(自由变量)已经由其语法环境完成闭合(或者绑定)的 lambda 表达式,从而形成了 闭合的表达式,或称闭包。

使用方法



C++语言中的Functions对象:

C++11标准开始支持闭包,这是一种特殊的函数对象,由特殊的语言结构—— lambda表达式 自动构建。

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;
}

1、声明闭包变量

C++中闭包的声明语法,要使用 function 类型来声明变量,如下所示

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

其中,第一个 float 代表了闭包的返回值类型,第二个 float 代表了闭包的参数数据类型为浮点型

2、赋值闭包变量

C++中闭包的赋值语法,要使用 [=] 或 [&] 符号开头,如下所示

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

其中, [=] 代表了我们将要进行的闭包传值是单向赋值

[&] 在使用过程中,经常作为引用传值使用,如下所示

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

3、使用闭包变量

使用 [=] 和 [&] 声明并且赋值后的闭包变量,在使用结束后的结果如下

//声明一个浮点型变量
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;
}

1、声明Block语法变量

float(^block)(float);

我们会发现,Blocks语法变量的声明语法与函数指针变量的声明语法 float(*pointer)(float); 非常类似,只是在运算符号上有区别;

2、赋值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 ("崔亚允");
		}
	}
}

1、声明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;
}

2、赋值C#语言中的Lambda表达式变量

在C#语言中,使用 => goes to 运算符来生成变量,如下所示:

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

=> goes to运算符的左边是闭包类型的浮点型参数,右边是闭包变量准备进行的逻辑运算,以 {} 包括。

3、使用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)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

需要注意的一点是

闭包一词经常和匿名函数混淆。这可能是因为两者经常同时使用,但是它们是不同的概念!!!!

时间: 2024-12-15 09:04:44

[iOS、Unity、Android] 浅谈闭包的使用方法的相关文章

浅谈 js 字符串 trim 方法之正则篇

position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流

浅谈设计模式3-模板方法模式

模版方法模式,个人认为还是用处比较多的一个设计模式,而且也是比较好学和理解的一个.依然来通过模拟一个场景来慢慢了解. 现在我们来实现一下泡茶这个过程.首先我们需要烧开一壶水,然后往茶壶中放茶叶,加入开水,等待茶泡好. 经过前两次的分享,大家应该具备了基本的面向对象的思想了,这里就不再用面向过程的方式演示了. 首先,有一种普通人,他泡茶的方式是这样的 public class Common     { public void MakeTea()         {             Heat

浅谈 js 对象 toJSON 方法

前些天在<浅谈 JSON.stringify 方法>说了他的正确使用姿势,今天来说下 toJSON 方法吧.其实我觉得这货跟 toString 一个道理,他是给 stringify 方法字符串化的时候调用的.看下 MDN 官方文档吧<toJSON behavior>.非常简单,但是要注意的是他和 stringify 方法第二个参数稍微有点不同.因为 stringify 第二个参数是回调函数时,只是对当前 key 对应的值进行修改.而 toJSON 则是对当前对象进行修改.例如: v

浅谈 js 字符串 search 方法

原文:浅谈 js 字符串 search 方法 这是一个很久以前的事情了,好像是安心兄弟在学习js的时候做的练习.具体记不清了,今天就来简单分析下 search 究竟是什么用的. 从字面意思理解,一个是搜索字符串吧. var str = "123456789abcde"; console.log( str.search("abc") ); // 9 确实是搜索指定字符在一个字符串中出现的位置,如果不存在就返回 -1可是这样就跟 indexOf 功能一样了,何必单独搞一

iOS应用架构浅谈

缘由 从事iOS工作一年多了,主要从事QQ钱包SDK开发和财付通app维护,随着对业务的慢慢熟悉,最近在思考这两款应用架构设计的思想,刚好昨天在微信里看了一篇iOS大牛对终端应用架构的分享,乘热打铁,下面浅谈下我对ios应用架构设计的理解,写的不好或不对的地方,欢迎大家拍砖,我们一起来探讨. 假如问你一个iOS or Android app的架构,你会从哪些方面来说呢? 不要急着给出你的答案,可以先在你的脑子里思考3分钟,再看下面我要讲的内容. 其实对于iOS客户端应用的架构来说,复杂度不亚于服

iOS开发&gt;学无止境 - 浅谈MVVM的架构设计与团队协作

李刚按:本文是青玉伏案写的一篇文章.相信大家对MVC耳熟能详,MVVM可能听说的相对少一些,这一篇文章将会想你阐述MVVM设计,还有团队协作的经验分享.如果你也觉得不错,就分享一下吧! demo:https://github.com/lizelu/MVVM 今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦~). 由 于本人项目经验有限,关于架构设

iOS开发之浅谈MVVM的架构设计与团队协作

今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦~). 由于本人项目经验有限,关于架构设计方面的东西理解有限,我个人对MVVM的理解主要是借鉴于之前的用过的MVC的Web框架~在学校的时候用过ThinkPHP框架,和SSH框架,都是MVC的架构模式,今天MVVM与传统的MVC可谓是极为相似,也可以说是兄弟关系,也就是一家人了. 说道架构设计和团队

iOS之block浅谈

前言 ios4.0系统已开始支持block,在编程过程中,block被Obj-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行.block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值.它和传统的函数指针很类似,但是有区别:block是inline的,并且它对局部变量是只读的. block和函数的相似性:(1)可以保存代码(2)有返回值(3)有形参(4)调用方式一样. block的使用 1.block的定义 // 声明和实现写在一起,就像变量的声明实现 int a

Android 浅谈 设计与屏幕适配

extends: http://www.ui.cn/detail/45435.html http://www.2cto.com/kf/201501/372699.html http://www.cnblogs.com/bluestorm/p/3640786.html http://www.shejidaren.com/android%E7%B3%BB%E7%BB%9F%E5%AD%97%E4%BD%93%E8%A7%84%E8%8C%83%E4%B8%8E%E5%BA%94%E7%94%A8%E