不同的编程语言如何使用闭包?

发布于 2024-08-04 15:32:41 字数 438 浏览 4 评论 0原文

据我所知,结合别人的知识,主流语言中

  • Objective C
  • C#
  • VB.net
  • Java
  • Python
  • Ruby
  • Javascript
  • Lisp
  • Perl

都有闭包和匿名函数。普通 C/C++ 不具备其中任何一个。

这些语言中的闭包具有相同的语义吗?它们对于日常编程有多重要?

一些背景:我一直在阅读有关 Objective C 的新内容,这些内容针对 Apple 的 Grand Central Dispatch,并且认为我应该了解是否真的只有一个< /em> 或不同方式将块状结构引入到语言中。

To my knowledge, combined with the knowledge of others, among the mainstream languages

  • Objective C
  • C#
  • VB.net
  • Java
  • Python
  • Ruby
  • Javascript
  • Lisp
  • Perl

have closures and anonymous functions. Plain C/C++ doesn't have either of those.

Do closures in these languages have the same semantics? How important are they for everyday programming?

Some background: I've been reading about the new additions to Objective C that target Apple's Grand Central Dispatch and thought I should learn whether there is really only one or different ways to introduce block-like structures into the language.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

誰認得朕 2024-08-11 15:32:41

请澄清您的问题:您所说的“工作”是什么意思?您如何使用它们、何时使用它们或者它们在内部是如何实现的?

.NET 语言 (VB/C#) 的编译过程可以向您展示闭包的一般表示方式:

闭包被转换为带有封闭变量字段的匿名类。访问闭包的函数指针(委托)只不过是匿名类实现的特殊方法上的指针。

关于闭包重要性的一些注释:

  • .NET:
    没有那么多明确使用闭包。匿名函数有时用于事件和数据的函数表示。主要用途是 LINQ 查询的(内部)表示。

  • Python:
    对匿名函数的支持很差 - 仅lambda vars: expr - 语法。

  • Javascript:整个函数语法只不过是围绕匿名函数和闭包的语法糖!

    函数 f(x) { return x + 1; }
    

    等于

    var f = function(x) { return x + 1; }
    
  • 红宝石:
    大量使用闭包:大多数程序流程结构都依赖于它们。
    参见

    array.each 做 |x|
       # 代码
    结尾
    

    只不过是对 array#each 函数的调用,并将要执行的匿名函数(块)作为参数传递。 C# 中的表示:

    Array.Each(x => {
        // 代码
    })
    红宝石

通常,闭包是这样的:

# Enclose `i` - Return function pointer
def counter():
    i = 0
    def incr():
        i += 1
        print(i)
    return incr

c = counter()
c() # -> 1
c() # -> 2
c() # -> 3

您枚举的所有语言(Java 除外 - 您有匿名类,而不是函数!)都将允许这样的事情。

Please clarify your question: What do you mean with work? How you use them, when they are used or how they are implemented internally?

The process of compilation of the .NET-languages (VB/C#) can show you how closures can be generally represented:

The closure is translated into an anonymous class with fields for the enclosed variables. The function pointer (delegate) to access the closure is nothing but a pointer on a special method implemented by the anonymous class.

Some notes on the importance of closures:

  • .NET:
    Not that much explicit usage of closures. Anonymous functions are sometimes used for events and functional representation of data. Main use is the (internal) representation of LINQ-queries.

  • Python:
    Poor support for anonymous functions - only lambda vars: expr - syntax.

  • Javascript: The whole function syntax is nothing but syntactic sugar around anonymous functions and closures!

    function f(x) { return x + 1; }
    

    equals

    var f = function(x) { return x + 1; }
    
  • Ruby:
    Heavy use of closures: Most program flow structures rely on them.
    See

    array.each do |x|
       # code
    end
    

    is nothing but a call of the array#each function with an anonymous function to be executed (block) passed as an argument. Representation in C#:

    Array.Each(x => {
        // Code
    })
    

Generally, a closure is something like this:

# Enclose `i` - Return function pointer
def counter():
    i = 0
    def incr():
        i += 1
        print(i)
    return incr

c = counter()
c() # -> 1
c() # -> 2
c() # -> 3

All the languages (except Java - You have anonymous classes, not functions!) you enumerated will allow things like this.

时间你老了 2024-08-11 15:32:41

主流语言之间的主要语义差异是是否允许更改闭包捕获的变量。 Java 和 Python 说不,其他语言说是(好吧,我不知道 Objective C,但其他语言都知道)。能够更改变量的优点是您可以编写如下代码:

public static Func<int,int> adderGen(int start) {
    return (delegate (int i) {      // <-- start is captured by the closure
                start += i;         // <-- and modified each time it's called
                return start;
            });
}
// later ...
var counter = adderGen(0);
Console.WriteLine(counter(1)); // <-- prints 1
Console.WriteLine(counter(1)); // <-- prints 2
// :
// :

您会注意到,这比等效计数器类的代码少得多,尽管 C#(此处使用的语言)在后面为您准确生成了该代码。场景。
缺点是捕获的变量确实是共享的,因此如果您在经典的 for 循环中生成一堆加法器,您会感到惊讶......

var adders = new List<Func<int,int>>();

for(int start = 0; start < 5; start++) {
    adders.Add(delegate (int i) {
        start += i;
        return start;
    });
}

Console.WriteLine(adders[0](1)); // <-- prints 6, not 1
Console.WriteLine(adders[4](1)); // <-- prints 7, not 5

不仅 start 在所有 5 个闭包之间共享,重复的 start++ 在 for 循环结束时赋予它值 5。在混合范式语言中,我的观点是 Java 和 Python 的想法是正确的——如果你想改变捕获的变量,你最好被迫创建一个类,这使得例如,当您将它们传递给构造函数时,捕获过程是显式的。我喜欢为函数式编程保留闭包。

顺便说一句,Perl 也有闭包。

The main intentional difference in semantics between the mainstream languages is whether to allow changes to variables captured by the closure. Java and Python say no, the other languages say yes (well, I don't know Objective C, but the rest do). The advantage to being able to change variables is that you can write code like this:

public static Func<int,int> adderGen(int start) {
    return (delegate (int i) {      // <-- start is captured by the closure
                start += i;         // <-- and modified each time it's called
                return start;
            });
}
// later ...
var counter = adderGen(0);
Console.WriteLine(counter(1)); // <-- prints 1
Console.WriteLine(counter(1)); // <-- prints 2
// :
// :

You'll notice that this is a lot less code than the equivalent counter class, although C# (the language used here) generates exactly that code for you behind the scenes.
The downside is that captured variables really are shared, so if you generate a bunch of adders in a classic for loop you are in for a surprise...

var adders = new List<Func<int,int>>();

for(int start = 0; start < 5; start++) {
    adders.Add(delegate (int i) {
        start += i;
        return start;
    });
}

Console.WriteLine(adders[0](1)); // <-- prints 6, not 1
Console.WriteLine(adders[4](1)); // <-- prints 7, not 5

Not only is start is shared across all 5 closures, the repeated start++ gives it the value 5 at the end of the for loop. In a mixed paradigm language, my opinion is that Java and Python have the right idea--if you want to mutate captured variables, you're better off being forced to make a class instead, which makes the capture process explicit, when you pass them to the constructor, for example. I like to keep closures for functional programming.

By the way, Perl has closures too.

许久 2024-08-11 15:32:41

Java 基本上在其设计中排除了闭包(尽管现在听起来可能很矛盾),因为他们希望在许多方面保持语言的简单性。

然而,自 day 1 v1.1 以来,Java 已经支持相同的功能,但它们不是混合范例(函数式 vs. OO),而是允许存在几乎用于相同目的的匿名内部类。由于它们不是闭包而是类,因此您必须输入更多字符。

因此,例如要拥有一个接收 TimerTask 作为要执行的块的 Timer,您可以编写:

 Timer timer = new Timer();

 timer.schedule( new TimerTask() {  // this is like the code block. 
     public void run() {
          System.out.println("Hey!");
     }
 },0);

正如您所看到的“TimerTask() { ...” 是匿名内部类的定义。该实例也可以分配给作为参数传递的变量。

TimerTask task = new TimerTask() {
     public void run() {
     }
 };


....
timer.schedule( task , 0 ) ;

你可以有这种类型的构造,但它们不是闭包。

是否将闭包添加到 Java 编程语言中仍然存在争议。

这是 Joshua Bloch 的有趣演讲: “闭包争议”

这是一篇关于“原理”的文章发展 Java 语言”

Java excluded the closures in their design, basically ( and although it may sound contradictory now ) because they wanted to keep the language simple in many aspects.

Since day 1 v1.1 however, Java have supported the same functionality, but instead of mixing paradigms ( functional vs. OO ) they allowed the existence of anonymous inner classes which pretty much serve for the same purpose. Since they are not closures but classes you have to type a few more characters.

So for instance to have a Timer which receives a TimerTask as block to be executed you would write:

 Timer timer = new Timer();

 timer.schedule( new TimerTask() {  // this is like the code block. 
     public void run() {
          System.out.println("Hey!");
     }
 },0);

As you see the "TimerTask() { ... " is the definition for the anonymous inner class. That instance could be assigned also to a variable an passed as argument.

TimerTask task = new TimerTask() {
     public void run() {
     }
 };


....
timer.schedule( task , 0 ) ;

You can have this kinds of constructs, but they are not closures.

Closures are still on debate to be added to the Java programming language.

Here's an interesting talk by Joshua Bloch: "The closures controversy"

Here is an article on "Principles for Evolving the Java Language"

清欢 2024-08-11 15:32:41

Java 没有闭包或匿名函数,尽管它有可以在某种程度上模拟这些的匿名类。

有一些相互竞争的提案要求在 Java 的下一版本中将闭包添加到该语言中,但这些提案都没有包含在官方更改列表中。

Java does not have closures or anonymous functions, although it does have anonymous classes that can be used to simulate these to some extent.

There were competing proposals to have closures added to the language in the next version of Java, but none of these have not been included in the list of official changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文