闭包的由来

要说闭包的由来就不得不先说下函数式编程了。近几年函数式编程也是比较火热,我们先来看看函数式编程的一些基本的特性这个有助于我们理解闭包的由来。

函数式编程

函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念。这里很明显的指出了函数式编程中最重要的就是函数而且是数学中的函数,比如f(x),数学中的函数最大的特点就是只要是同样的参数x那么我的结果必定是相等的,也就是说我们函数的返回值只是依赖于参数而不依赖于其他状态(比如js中的全局变量就是一个干扰因素);后一句中说避免变量的概念,这句话如果从函数式编程来说不太恰当,因为这句话中的函数意思还是我们在编程语言中所使用的变量也就是一个存储单元,而在函数式编程中变量却是数学中变量的定义是一个值得名称。比如,我们最基本的赋值等式 x = x+1,让我们程序员看这是一个简单的赋值代码,而让学数学的人来说这个等式是根本不成立的。 所以我们在函数式编程中是不允许多次赋值的。而这一句话也是讲述了函数式编程好处的最主要的原因:

第一点、函数的结果只依赖于参数而不依赖其他状态,这样写的代码很容易进行推理不容易发生错误,极大的方便的单元测试和调试。

第二点、因为不可变性和无状态,那么我们在处理多个线程之间就不用担心资源的争夺,不需要用锁来保存状态。

高阶函数

函数式编程中函数是一等公民,和我们的口号 "万物皆对象"有点相似,在函数式编程中,我们努力用函数来表达所有的事情,当然我们也需要函数可以传过来传过去这就是高阶函数,也就是把函数作为参数或者返回值,继而实现复用,这样即是可以把复用的粒度降到函数。C#语言中也有类似的东西--委托,当然C#中的函数跟函数式编程中的就不一样了,但是有吸收一些函数式编程语言中的特性,比如C#中lamda,Linq。

关于函数式编程博客园有很多很好的文章介绍我就不详说了,接下来就是引出我们今天的主题--闭包。

因为函数式编程的基础就是Lambda演算,所以这一节演算我们用Lambda演算来带出我们的主题,关于这个演算我也懂得不是太多,想要入门的同学可以看看这个  点这里

首先定义一个简单的演算

λx.λy.x+y

如果x为1 y为2 演算过程则为

((λx.λy.x+y)1)2=(λy.1+y)2=(1+2)=3

接下来我们用到高阶函数

λy . (λx . x + y)

演算过程:

((λy . (λx . x + y))1)2=((λx . x + 1))2 = (2+1)=3

可以看到这个演算中外层函数使用的是内层函数,也就是说使用是一个函数作为了计算结果。OK ,我们把内层函数单独拿出来,(λx . x + y),可以很明显的看到如果脱离的上下文呢,我们的y是没有值的,也就是y是没有绑定的,也可以说y对于我们这个函数是自由的! 如果在函数式编程中,在外层函数执行完毕之后我们的y变量就应该被销毁,那么如果我们在内层函数中如果还需要用到y的话怎么办呢? 对于这个问题,设计者则做了其他的处理:如果一个函数返回另一个函数,而被返回函数又需要外层函数的变量时,不会立即释放这个变量,而是允许被返回的函数引用这些变量。支持这种机制的语言称为支持闭包机制,而这个内部函数连同其自由变量就形成了一个闭包(这句话是摘自其他博客,自己难得整理文字。。。)。这就是我们闭包的由来,而我们其他的语言如果有用到函数式编程的思想,并且允许函数来进行传递就会遇到类似的问题,所以各个语言就需要用其自己的方式来实现闭包!

C#中闭包的实现

从上一节我们也就是能总结出闭包其实就是要执行并且包含自由变量的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境的一个结合。

然后进入我们的C#编程时刻了,我们就用简单的例子来实现,并且查看编译器生成的代码 看看C#中是怎么实现闭包,毕竟我们也是有委托的 。。。

首先写一个简单得不能在简单的代码

 using System;

 namespace closure
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(test()());
Console.ReadKey();
} public static Func<int,int> test(int x)
{
//作用域1
return (y) =>
{
//作用域2
return x + y;
};
}
}
}

可以看到我们test的方法中传入变量x的作用域是在1 在执行匿名函数的时候应该是已经释放在作用域2就不应该存在了,而我们却能准确的得到计算结果

说明我们的变量x确实在作用域2中还存在,接下来我们看看编译器帮我们做了什么事情,

可以看到我们的test方法中多了一个对象 <>c__DisplayClass1_0  class_;这个东西的具体定义是啥?

这个很明显了,其实闭包只是编译器帮我们把自由变量封装到了一个对象中供我们作用域外使用,那我们如果去掉作用域2中使用x变量呢?

编译器原来为了自由变量维护的对象没了 。。。结果在意料之中。

OK,这篇文章就到此结束了,关于闭包是python中啊 js中啊 或者C#中得用处我就不细说了,博客园中有太多太多的介绍了,希望这边文章对你有帮助,欢迎拍砖!

C#温故而知新系列 -- 闭包的更多相关文章

  1. sql server 基础教程[温故而知新三]

    子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识如果 ...

  2. jquery 基础教程[温故而知新二]

    子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识如果 ...

  3. javascript 基础教程[温故而知新一]

    子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识如果 ...

  4. Spring MVC (二)注解式开发使用详解

    MVC注解式开发即处理器基于注解的类开发, 对于每一个定义的处理器, 无需在xml中注册. 只需在代码中通过对类与方法的注解, 即可完成注册. 定义处理器 @Controller: 当前类为处理器 @ ...

  5. SQLServer 用法简例

      子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识 ...

  6. 深入理解javascript原型和闭包系列

    从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...

  7. JavaScript 闭包系列二(匿名函数及函数的闭包)

    一. 匿名函数 1. 函数的定义,可分为三种 1) 函数声明方式 function double(x) {     return 2*x; } 2)Function构造函数,把参数列表和函数体都作为字 ...

  8. 《深入理解javascript原型和闭包系列》 知识点整理(转)

    深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...

  9. 《深入理解javascript原型和闭包系列》 知识点整理

    深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...

随机推荐

  1. 操作系统 - Linux进程实现的内部结构

    在进程描述符中进入几个字段来表示进程之间的父子关系和兄弟关系. 图3-4显示了一组进程间的亲属关系. 表3-4:建立非亲属关系的进程描述符字段 在某些情况下,内核必须能从进程的PID到处对应的进程描述 ...

  2. 记——加快gradle 构建速度的经验

    Gradle作为一个新的构建系统,无疑在灵活,扩展,跨平台等各方面都表现得非常优秀,然而,它也有一点备受吐槽,就是速度慢.以下为本人使用gradle过程中,几次加快gradle构建速度的经验之谈. 本 ...

  3. IOS中的数据存储方式,特点,使用情况

    数据存储的核心都是写文件,主要有四种持久化方式:属性列表(Plist),对象序列化,SQLite数据库,CoreData. 存储Plist: 键值进行存储,不能存储对象.对象需要序列化编码才能写入文件 ...

  4. Redis的集群配置

    如果我们redis的压力很大,如果我们的并发高到我们读数据和写数据都有了很大压力. 那么我们可能就需要把redis分开部署,并且配置为一个『主从』的状态. 在服务器上构筑Redis的集群配置: 1.切 ...

  5. python下实现二叉堆以及堆排序

    python下实现二叉堆以及堆排序 堆是一种特殊的树形结构, 堆中的数据存储满足一定的堆序.堆排序是一种选择排序, 其算法复杂度, 时间复杂度相对于其他的排序算法都有很大的优势. 堆分为大头堆和小头堆 ...

  6. MOOS学习笔记3——命令行

    MOOS学习笔记3--命令行 例程 /** * @code A simple example showing how to use a comms client问问怎么样 */ #include &q ...

  7. JVM学习--(四)垃圾回收算法

    我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. stop the world 在介绍垃圾 ...

  8. <转>如何在iOS 7中设置barTintColor实现类似网易和 Facebook 的 navigationBar 效果

    转自:i‘m Allen的博客 先给代码:https://github.com/allenhsu/CRNavigationController 1. 问题的表现 相信很多人在 iOS 7 的适配过程中 ...

  9. 远离压力,提高效率——Getting things done读书笔记

    一.确定时间.空间和工具   二.收集阶段:填充工作篮         1. 这有助于你认识到自己面对的工用量.         2. 同时让你清楚"隧道的终点"在哪        ...

  10. ssh优缺点

    面试归来 技术面试官叫我谈谈 ssh优缺点 平时用起来倒是挺顺手..但是从来没有系统的总结过..导致很多点会都没有说出来.. 这次我认真总结了一下... 常说的好处 开源 常说的坏处 配置文件过大我就 ...