6

我不明白闭包如何比类更强大。看起来我可以使用类实现相同的闭包行为。任何帮助,将不胜感激

4

5 回答 5

11

闭包是穷人的对象/对象是穷人的闭包

请参阅:闭包和对象

对于懒人:

尊贵的 Qc Na 大师与他的学生 Anton 同行。安东希望能引起大师的讨论,道:“大师,我听说物件是一个很好的东西,这是真的吗?” Qc Na 怜悯地看着他的学生,回答说:“愚蠢的学生 - 对象只是一个穷人的闭包。”

受到责备后,安东离开了他的主人,回到了他的牢房,一心研究闭包。他仔细阅读了整个“Lambda: The Ultimate...”系列论文及其表亲,并实现了一个带有基于闭包的对象系统的小型 Scheme 解释器。他学到了很多,并期待着向他的主人通报他的进步。

在与 Qc Na 的下一次散步中,Anton 试图打动他的师父,他说:“师父,我已经认真研究了这件事,现在明白了物体确实是穷人的闭包。” Qc Na 用棍子击打 Anton 回应说:“你什么时候才能学会?闭包是穷人的对象。” 那一刻,安东顿悟了。

—<a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html" rel="nofollow noreferrer">Anton van Straaten

于 2009-04-27T22:50:02.303 回答
4

Aclosure和 aclass是两个非常不同的东西。

class说“A 比 a更强大”是不正确的closure。反之亦然。

他们做完全不同的事情。

Aclosure在基本意义上是一个函数调用,它保留了它创建的范围内的局部变量信息。

Aclass是对象的定义。类定义了类实例的行为和内容。

于 2009-04-27T22:38:28.273 回答
4

其他人已经解释了类和闭包之间的区别。我只是想指出,在 Java API 中支持它们的语言会/可能使用闭包的许多地方,都会使用接口的匿名实现。例如考虑下面的代码:

JButton btn = new JButton("Say Hello");
btn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageBox("Hello");
    }
});

在这种情况下,可以说匿名 ActionListener 充当了一个闭包,如果 Java 允许闭包,代码可能如下所示:(使用 c++0x-esque 语法)

JButton btn = new JButton("Say Hello");
btn.addActionListener([]=>(ActionEvent e){JOption.showMessageBox("Hello");});

在这个简单的例子中,闭包和接口(AII)的匿名实现之间的主要区别在于:

  1. AII 方法比闭包具有更强的类型检查。(可以使闭包系统具有更强的类型检查,但一般来说,它们不是)
  2. 闭包语法需要更少的输入。这似乎是一旦你咀嚼 Java 需要闭包参数足够长的时间呈现出来的主要抱怨。

我还没有遇到过 AII 无法做需要做的事情的情况。是的,需要定义更多类型和另一个接口,但是它们的系统可以工作,而且恕我直言,更强大,因为您不需要使用 AII,而是可以使用具有自己的方法、成员数据和构造函数的成熟类. 一个示例是弹出上下文菜单的动作侦听器。如果您创建一个实现 ActionListener 并以 JMenu 作为参数的类,您可以执行以下操作:

btn.addActionListener( new ContextMenuActionListener(myMenu) );

这看起来比 boost:bind 类型的解决方案更干净(对我来说)。

[]=>(ActionListener) myContextPopupClosure = []=>(ActionListener E){ ... };
...
btn.addActionListener( Closure.bind1(myContextPopupClosure,myMenu) );

或者

编辑:

在昨晚做了很多关于泛型的工作之后,我意识到了闭包优于 AII 的一个优势。在上面的例子中,我一直假设闭包的类型是 []=>(ActionEvent),但它实际上可能是类型 []=>(? super ActionEvent)。这表示:

[]=>(Object) c = []=>(Object o) { System.exit(0); }
btn.addActionClosure( c );
window.addMouseMovedClosure( c );
//Each method in MouseMotion listener would need it's own closure.
//So I 'invented' an API change.

将是可编译的。这可能很有用,因为当您需要做同样的事情来响应多个事件时。

另一个例子。这个闭包可以添加到任何需要闭包的地方。如果添加到 ActionListener 或 MouseListener 中,它会记录调用。

[]=>(Object ... objs) log = []=>(Object ... obj) {for(Object o:obj){logObject(o);}}
于 2009-04-28T01:46:20.367 回答
2

这是一个很好的问题,但措辞可能更好:

“Java 对象和 JavaScript 闭包之间有哪些相同点和不同点”?

相似之处:它们都在局部变量中具有持久状态。他们的方法可以访问这些状态变量。

区别:Javascript是一种函数式语言,因此函数中的函数可以立即调用和返回。例如:

newXY = function(x,y) {

    var that = {};//Instantiate new object
    var x = parseFloat(x);
    var y = parseFloat(y);

    that.xtimesy = function() {
      return x*y;
    }(); // <-- Notice the immediate invocation of the function, here.

    return that;
};

所以你可以编写这样的代码,从rhino shell复制/粘贴:

js> var foo = newXY(2,5);
js> foo.xtimesy;
10
于 2009-04-28T05:09:02.203 回答
2

我不确定是什么导致您提出这个问题,但是您被告知的某些内容或您阅读的某些内容严重误导了您。

完全忽略语言,闭包是编程中完全不相关的结构/约定。

于 2009-04-27T22:39:19.317 回答