zoukankan      html  css  js  c++  java
  • 闭包

    昨天跟几个朋友闲谈时,提到C++的函数指针与C#的方法对象,其中讨论了一个在学习C#中很少提到的概念"闭包"

    闭包

    闭包是将一些执行封装,将它像对象一样传递,

    在传递时,执行依然能够访问到原上下文。

    访问原来上下文,是闭包的重要特征

    例:

    由于只声明了一个i变量

    所以所有的Action捕获的都是同一个i变量。结果就是每一行都输出数字10

    static void Main(string[] args)

    {

    List<Action> ls = new List<Action>();

    for (int i = 0; i < 10; i++)

    {

    ls.Add(() => Console.WriteLine(i));

    }

    foreach (Action action in ls)

    {

    action();

    }

    System.Console.Read();

    }

    以下方式实现了输出0到9

    与上例代码的唯一不是是在循环体中使用了一个局部变量tp,这种写法在通常看来不通是多用了一个中转变量,对程的执行不会有什么影响,但事实上tp这个变量在被每个Action独立保存.

    这样,每次循环体在执行的时候,都会取得一个全新的tp,而且tp不会因为所在声名体的完成而出栈

    static void Main(string[] args)

    {

    List<Action> ls = new List<Action>();

    for (int i = 0; i < 10; i++)

    {

    int tp = i;

    ls.Add(() => Console.WriteLine(tp));

    }

    foreach (Action action in ls)

    {

    action();

    }

    System.Console.Read();

    }

    若匿名方法中的变量:

    若匿名方法中如果引用了某个变量,则该局部变量将被提升为实例变量,并储存于一个叫做闭包(closure)的对象中。

    提升之后,即使创建该变量的方法执行完毕该变量仍不会消亡。

    当指向该匿名函数的所有引用都消失后,该闭包变量即可正常地被垃圾回收器回收

    说明

    class Program

    {

    delegate int wxd(int i);

    delegate wxd lzm(int ii);

    static void Main(string[] args)

    {

    lzm obj = delegate(int ii)

    {

    return

    delegate(int i)

    {

    return i + ii;

    };

    };

    wxd w1 = obj(1);

    wxd w2 = obj(2);

    System.Console.WriteLine(w1(3));

    System.Console.WriteLine(w2(3));

    System.Console.Read();

    }

    }

    输出的结果是4和5

    [obj]函数接受一个参数,返回新的函数[w1,w2]。新的函数[w1,w2]将[obj]的参数与自己的参数相加,返回结果

    函数[w1,w2]在接受相同的参数的时候,产生了不同的结果。

    实际上[obj]返回的内部函数已经把[obj]的参数[ii]记录了

    在这里,方法已不仅仅是一个函数指针了

    [obj]的参数[ii]是如何记录的:

    通常理解,函数的参数是放在栈中的。

    如果闭包也将参数放在栈中,那么[ii]在[obj]运行结束的时候就会消失掉,这个时候[w1,w2]再通过栈去搜索[ii]显然就是不可能的。

    所以闭包中参数或内部变量不能放在栈中.而是放在程序执行过程之中的一张全局表里.

    [[obj]在返回内部函数的时候,将全局表,自己的结构表,内部函数的指针一起传递给变量[w1,w2].

    这时内部函数可以访问[ii],外部却无法访问[ii]

  • 相关阅读:
    【bzoj1174】[Balkan2007]Toponyms Trie树
    【bzoj1786】[Ahoi2008]Pair 配对 dp
    【bzoj3956】Count 单调栈+可持久化线段树
    【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree
    【bzoj3696】化合物 树形dp
    【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆
    【bzoj3671】[Noi2014]随机数生成器 贪心
    【bzoj4653】[Noi2016]区间 双指针法+线段树
    【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp
    用Python操作Named pipe命名管道,实用做法——os.read 或 os.write
  • 原文地址:https://www.cnblogs.com/foundation/p/1352797.html
Copyright © 2011-2022 走看看