在调用具名匿名函数和常规子例程之间的区别。

huangapple go评论52阅读模式
英文:

Difference between calling named anonymous function and regular subroutine

问题

以下是翻译好的内容:

我正在Perl中尝试匿名函数,并且开始思考调用这两者之间的区别:

my $read_file = sub {
    my ($filename) = @_;
    my @lines;
    
    open my $fh, '<:raw', $filename or die "无法打开文件 $filename: $!";
    while (my $line = <$fh>) {
        chomp $line;
        push @lines, $line;
    }
    close $fh;
    return @lines;
};

和这个:

sub read_file {
    my ($filename) = @_;
    my @lines;
    
    open my $fh, '<:raw', $filename or die "无法打开文件 $filename: $!";
    while (my $line = <$fh>) {
        chomp $line;
        push @lines, $line;
    }
    close $fh;
    return @lines;
}

希望这对你有所帮助。

英文:

I'm experimenting with anonymous functions in Perl, and I began to wonder what the difference between calling these two is:

my $read_file = sub {
    my ($filename) = @_;
    my @lines;
    
    open my $fh, &#39;&lt;:raw&#39;, $filename or die &quot;Can&#39;t open file $filename: $!&quot;;
    while (my $line = &lt;$fh&gt;) {
        chomp $line;
        push @lines, $line;
    }
    close $fh;
    return @lines;
};

And this:

sub read_file {
    my ($filename) = @_;
    my @lines;
    
    open my $fh, &#39;&lt;:raw&#39;, $filename or die &quot;Can&#39;t open file $filename: $!&quot;;
    while (my $line = &lt;$fh&gt;) {
        chomp $line;
        push @lines, $line;
    }
    close $fh;
    return @lines;
}

答案1

得分: 4

sub foo { ... }

等同于

use Sub::Name qw( subname );

BEGIN { *foo = subname foo => sub { ... }; }

这说明以下差异:

sub foo { ... } my $foo = sub { ... };
编译 在编译时执行一次。 在编译时执行一次。
子程序名称 名称为 foo。这可以通过 caller 返回,并且在诸如 Carp::confess 之类的堆栈跟踪中找到。 未命名,除非像上面所示使用 subname 或类似的方式。不命名可能导致令人沮丧的错误消息。
变量作用域 子程序分配给 *foo{CODE},在整个程序中可见(经过适当限定)。这允许导出它。如果要限制其作用域,可以使用 my sub foo { ... } 子程序分配给 my $foo,这是一个词法变量。它仅在找到它的词法作用域中可见。使用 our $foo 或全局变量可以扩展该作用域,如果需要的话。
赋值时机 子程序在编译子程序时分配给 *foo{CODE}。这也是捕获外部变量的时机。 子程序在评估赋值时分配给 $foo。这也是捕获外部变量的时机,因此每次评估语句时都会创建一个新的闭包。
原型 调用遵循子程序的原型。 通过引用调用会忽略子程序的原型。

<details>
<summary>英文:</summary>

```perl
sub foo { ... }

is equivalent to

use Sub::Name qw( subname );

BEGIN { *foo = subname foo =&gt; sub { ... }; }

This illustrates the following differences:

sub foo { ... } my $foo = sub { ... };
compiled Once, at compile-time. Once, at compile-time
sub's name Named foo. This is returned by caller, and it's found in stack traces such as those from Carp::confess. Unnamed, unless subname or similar is used as shown above. Leaving it unnamed could lead to frustrating error messages.
variable's scope The sub is assigned to *foo{CODE}, which is visible to the entire program (with proper qualification). This permits its exportation. If you want to restrict its scope, you can use my sub foo { ... }. The sub is assigned to my $foo, which is a lexical variable. It's only visible in the lexical scope in which it is found. Using our $foo or a glob would expand that scope if so desired.
assignment's timing The sub is assigned to *foo{CODE} when the sub is compiled. This is also when external variables are captured. The sub is assigned to $foo when the assignment is evaluated. This is also when external variables are captured, so each evaluation of the statement creates a new closure.
prototype Calls honour the sub's prototype. Calling via a reference ignores the sub's prototype.

答案2

得分: 3

最大的、实际上也很重要的区别在于,命名子例程在编译时创建,并位于符号表(全局),而匿名子例程(代码引用)在运行时创建,并且局部于其创建的范围内(可以分配给词法变量)。

因此,代码引用可以在范围内创建和使用,外部无法看到,就像“local”子例程一样,它可以用于闭包等。命名子例程则不行。

但是在调用它们方面,只是 subname(ARGS LIST)$coderef->(ARGS LIST) 的区别。

问题标题中使用的短语“命名匿名”是不准确的——它要么是命名的,要么是匿名的(代码引用)。

在较新的 Perl 版本中,我们确实拥有真正的局部子例程,词法(私有)子例程

英文:

The biggest, and practically important, difference is that the named subroutine is created at compile time and is in the symbol table (global), while an anonymous one (a code reference) is created at runtime and is local to the scope in which it is created (and can be assigned to a lexical variable).

So a code reference can be created and used within a scope and not be seen outside, like a "local" subroutine<sup>&dagger;</sup>, it can be used for a closure, etc. A named subroutine cannot.

But as for calling them, it's just subname(ARGS LIST) vs $coderef-&gt;(ARGS LIST).

The phrase used in the question's title, "named anonymous" is a misnomer -- it is either named or anonymous (a code reference).


<sup>&dagger;</sup>
In newer Perls we do have truly local subs, lexical (private) subroutines

huangapple
  • 本文由 发表于 2023年4月19日 16:04:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76052075.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定