代码之家  ›  专栏  ›  技术社区  ›  koen

闭包:为什么它们如此有用?

  •  54
  • koen  · 技术社区  · 15 年前

    作为 OO

    10 回复  |  直到 15 年前
        1
  •  72
  •   Stack Overflow is garbage    15 年前

    您可以将其视为类的泛化。

    你的班级有一些状态。它的方法可以使用一些成员变量。

    闭包只是一种更方便的方法,可以让函数访问本地状态。

    您不必创建一个知道您希望函数使用的局部变量的类,只需当场定义函数,它就可以隐式访问当前可见的每个变量。

    当您用传统的OOP语言定义一个成员方法时,它的闭包是“这个类中所有可见的成员”。

    具有“适当”闭包支持的语言简单地概括了这一点,因此函数的闭包是“此处可见的所有变量”。如果“ “是一个类,那么你有一个传统的类方法。

    如果“ 在这里

    因此,这只是一种泛化,消除了“函数只能在类内定义”的愚蠢限制,但保留了“函数可以看到在声明点上可见的任何变量”的想法。

        2
  •  30
  •   JW.    4 年前

    对我来说,闭包最大的好处是当您编写代码来启动任务、让任务运行并指定任务完成时应该发生什么时。通常,在任务结束时运行的代码需要访问开始时可用的数据,而闭包使这变得容易。

    例如,JavaScript中的一个常见用法是启动HTTP请求。无论是谁启动它,都可能想控制响应到达时发生的事情。所以你可以这样做:

    function sendRequest() {
      var requestID = "123";
      $.ajax('/myUrl', {
        success: function(response) {
          alert("Request " + requestID + " returned");
        }
      });
    }
    

    由于JavaScript的闭包,“requestID”变量被捕获到success函数中。这显示了如何在同一位置编写请求和响应函数,并在它们之间共享变量。如果没有闭包,您需要将requestID作为参数传入,或者创建一个包含requestID和函数的对象。

        3
  •  29
  •   Gregory Mostizky    15 年前

    闭包不会给你任何额外的能量。

    但它们对于使代码更清晰易读非常有用。

    让我给您举一个可能用法的简短Java示例:

        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                System.out.println("Pressed");
            }
        });
    

    将替换为(如果Java有闭包):

    button.addActionListener( { System.out.println("Pressed"); } );
    
        4
  •  5
  •   Martin    15 年前

    它们的上下文将在以后的某个时候被引用,并在需要时执行。

    可以 使代码编写/管理更加简单和干净。

    [编辑-基于上述评论的代码示例]

    爪哇:

    List<Integer> numbers = ...;
    List<Integer> positives = new LinkedList<Integer>();
    for (Integer number : integers) {
        if (number >= 0) {
            positives.add(number);
        }
    }
    

    Scala(跳过其他一些细节,如类型推断和通配符,因此我们只比较闭包的效果):

    val numbers:List[Int] = ...
    val positives:List[Int] = numbers.filter(i:Int => i >= 0)
    
        5
  •  5
  •   blabla999    14 年前

    遗憾的是,人们不再在教育大学学习闲聊;在那里,闭包用于控制结构、回调、集合枚举、异常处理等。

    |actionQueue|
    
    actionQueue := SharedQueue new.
    [
        [
            |a|
    
            a := actionQueue next.
            a value.
        ] loop
    ] fork.
    
    actionQueue add: [ Stdout show: 1000 factorial ].
    

    对于那些不能阅读Smalltalk的人,JavaScript语法也是如此:

    var actionQueue;
    
    actionQueue = new SharedQueue;
    function () {
        for (;;) {
            var a;
    
            a = actionQueue.next();
            a();
        };
    }.fork();
    
    actionQueue.add( function () { Stdout.show( 1000.factorial()); });
    

    编辑:注意actionQueue是如何从块内部引用的,这甚至适用于分叉线程块。这就是闭包如此易于使用的原因。

        6
  •  3
  •   Jesper    15 年前

    以下是一些有趣的文章:

        7
  •  3
  •   Peter Mortensen stimpy    15 年前

    举个例子,考虑C 3:它有闭包和许多其他功能方面,但仍然是一个非常面向对象的语言。

    根据我的经验,C的功能方面# 为了留在类成员的实现中,而不是作为公共API的一部分,我的对象最终会公开。

    因此,闭包的使用往往是面向对象代码中的实现细节。

    我一直在使用它们,因为这段代码片段来自我们的一个单元测试(针对 Moq )显示:

    var typeName = configuration.GetType().AssemblyQualifiedName;
    
    var activationServiceMock = new Mock<ActivationService>();
    activationServiceMock.Setup(s => s.CreateInstance<SerializableConfigurationSection>(typeName)).Returns(configuration).Verifiable();
    

    如果没有C#的闭包特性,将输入值(typeName)指定为模拟期望的一部分将非常困难。

        8
  •  0
  •   Dexygen    13 年前

    至于最后一个问题:“闭包是否适合OO世界?”

    在许多语言中,闭包,以及一流的功能,为设计面向对象程序提供了基础:JavaScript、Lua和Perl。

    在我熟悉的另一种“传统”OO语言Java中,有两个主要区别:

    1. 功能是 第一类构造

    因此,在Java这样的“传统OO”语言中,闭包的添加在很大程度上只是语法上的糖分。

        9
  •  -2
  •   Peter Mortensen stimpy    15 年前

    也许在编译编程的世界中,闭包的好处不那么明显。在JavaScript中,闭包的功能非常强大。这有两个原因:

    1) JavaScript是一种解释语言,因此指令效率和名称空间保护对于大型程序或评估大量输入的程序更快、响应更快地执行非常重要。

    2) JavaScript是一种lambda语言。这意味着JavaScript函数是定义作用域的第一类对象,并且子对象可以访问父函数的作用域。这一点很重要,因为变量可以在父函数中声明、在子函数中使用,甚至在子函数返回后也可以保留值。这意味着一个变量可以被一个函数多次重用,其值在该函数的最后一次迭代中已经定义。

    因此,闭包的功能非常强大,在JavaScript中提供了卓越的效率。

        10
  •  -2
  •   sdsadsadsada    11 年前

    看看上面的例子,我可以补充一下。

    • 我欣赏风格、隐藏部分和表达链,但这还不够

    • 我觉得Scala、Perl和其他一些Scheme类型的语言是为了简化语言设计者的特定思维方式而设计的,或者使它们“更有效率”

    我会将python的简单性和java的早期语法等作为简单性和明确性的更好方式

    在狭小的空间中编写神秘的链式闭包可能相当快。然而,一切都可以通过简单的对象和算法来完成

    关闭是必要的,但并非经常需要,以保证他们是一等公民。