IT技术博客大学习 共学习 共进步

什么是闭包(Closure)?

外刊IT评论 2011-08-14 15:51:35 浏览 3,764 次
本文是从 What is a Closure? 这篇文章翻译而来。

    这个问题是在最近一次英格兰Brighton ALT.NET Beers活动中提出来的。我发现,如果不用代码来演示,你很难单用话语把它解释清楚,所以,在这里,我打算用C#来解释一下什么是闭包(closures)。维基百科上说

    在计算机科学中,闭包�-losure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

    所以,一个闭包就是一个“捕获”或“携带”了其被生成的环境中、所属的变量范围内所引用的所有变量的函数。的确,很难描述,但当你看完了这些代码后,你就很容易理解了。

var x = 1;

Action action = () =>
{
    var y = 2;
    var result = x + y;
    Console.Out.WriteLine("result = {0}", result);
};

action();

    这里我们首先定义了一个变量“x”,值为1。然后我们定义了一个匿名函数(一个lambda表达式)赋给类型Action。Action没有参数,没有返回值,但如果你观察“action”里的定义,你会发现它使用了“x”变量。这是变量是被action“捕获”或“携带”的,自动被添加到了action的运行环境中了。

    当我们执行acton时,它输出了我们预期的结果。请注意,当我们执行时,原始的“x”此时已经脱离了它当初的变量环境,但它仍然能用。

    当你在代码调试器(debugger)里观察“action”时,会发现很有趣的事情。我们可以看到,C#编译器为我们创建了一个Target类,里面封装了x变量:

    closure_in_debugger

    闭包(和higher order functions)都是非常有用的东西。如果你曾经开发过稍微复杂一点的Javascript程序,你可能就会知道,这个东西可以被当成很多面向对象特征的替代品,就像C#那样。前不久我还在C#里写了一个例子来验证这种想法。

    习惯性的,John Skeet给了闭包一个更详细的描述。更详细的信息请查看《深入解析C#》里的这一章。里面还介绍了你在闭包里会经常会遇到的一些错误。

建议继续学习

  1. for 循环为何可恨? (阅读 5,383)
  2. 理解Javascript的闭包 (阅读 4,745)
  3. GC与JS内存泄露 (阅读 4,603)
  4. JavaScript的闭包问题 (阅读 4,303)
  5. 在回调和闭包中的内存泄漏 (阅读 3,983)
  6. 闭包漫谈(从抽象代数及函数式编程角度) (阅读 3,782)
  7. 闭包与作用域 (阅读 3,722)
  8. 闭包漫谈(从抽象代数及函数式编程角度) (阅读 3,722)
  9. 前端代码之丑(一):分支化技巧 (阅读 3,540)
  10. Perl闭包实例解释 (阅读 3,061)