闭包的由来

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

函数式编程

函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念。这里很明显的指出了函数式编程中最重要的就是函数而且是数学中的函数,比如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. mysql进阶(十五) mysql批量删除大量数据

    mysql批量删除大量数据 假设有一个表(syslogs)有1000万条记录,需要在业务不停止的情况下删除其中statusid=1的所有记录,差不多有600万条, 直接执行 DELETE FROM s ...

  2. 嵌入式C快速翻转一个任何类型的数的二进制位

    unsigned char reverse_bits(unsigned char value) { unsigned char answer , i ; answer = 0 ; for(i = 1 ...

  3. Android进阶(十八)AndroidAPP开发问题汇总(二)

    Android进阶(十八)AndroidAPP开发问题汇总(二) 端口被占用解决措施: Android使用SimpleAdapter更新ListView里面的Drawable元素: http://ww ...

  4. DB Query Analyzer 6.01 is released, SQL Execute Schedule function can be used

       DB Query Analyzer is presented by Master Gen feng, Ma from Chinese Mainland. It has English versi ...

  5. javascript、ruby和C性能一瞥(3) :上汇编

    在博文(1)和(2)里分别用了4中方式写一个素数筛选的算法,分别是javascript in browser.node.js.ruby和c:最终的结果是c最快,node.js其次,js in b虽然也 ...

  6. java 深入理解内部类以及之间的调用关系

    什么是内部类 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能使用public和 ...

  7. Python_linux环境变量和软链接(个人理解)

    --------------------------------------- 最近在服务器上想运行个脚本,装了个python3.6,但是他还自带了个2.7版本,后来发现上面还有3.5版本的pytho ...

  8. spiral matrix 螺旋矩阵

    Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...

  9. <h1>02_Linux学习_命令</h1>

    帮助命令:        xxx --help        man xxx 列出当前目录下的目录和文件:        ls        ls -l        ls --help        ...

  10. db2 查新索引 主键 sql

    1.查询主键 select * from sysibm.syskeycoluse where tbname='...' 2.查询索引 select * from sysibm.indexs where ...