我什么时候应该使用 &调用 Perl 子例程?

发布于 2024-08-03 16:53:34 字数 256 浏览 10 评论 0原文

我听说人们不应该使用 & 来调用 Perl subs,即:

function($a,$b,...);
# opposed to
&function($a,$b,...);

我知道参数列表是可选的,但是在某些情况下适合使用 & 以及您绝对不应该使用它的情况?

另外,当省略 & 时,性能的提高如何发挥作用?

I have heard that people shouldn't be using & to call Perl subs, i.e:

function($a,$b,...);
# opposed to
&function($a,$b,...);

I know for one the argument list becomes optional, but what are some cases where it is appropriate to use the & and the cases where you should absolutely not be using it?

Also how does the performace increase come into play here when omitting the &?

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

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

发布评论

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

评论(4

一梦等七年七年为一梦 2024-08-10 16:53:34

我经常滥用 &,但主要是因为我正在做一些奇怪的界面内容。如果您不需要这些情况之一,请不要使用 &。其中大多数只是访问子程序定义,而不是调用子程序。一切都在 perlsub 中。

  1. 获取对命名子例程的引用。这可能是大多数 Perler 唯一常见的情况:

     我的 $sub = \&foo;
    
  2. 同样,分配给 typeglob,它允许您使用不同的名称调用子例程:

     *bar = \&foo;
    
  3. 检查子例程是否已定义,就像在测试套件中一样:

     if( 已定义 &foo ) { ... }
    
  4. 删除子例程定义,这不应该是常见的:

     undef &foo;
    
  5. 提供一个调度程序子例程,其唯一的工作是选择要调用的正确子例程。这是我使用 &调用子例程的唯一情况,并且当我希望多次调用调度程序并且需要从子例程中挤出一点性能时操作:

    <前><代码>子figure_it_out_for_me {
    # 所有这些都重新使用当前的@_
    if( ...某些条件... ) { &foo }
    elsif( ...其他一些... ) { &bar }
    否则{&默认}
    }

  6. 使用当前参数堆栈跳转到另一个子例程(并替换调用堆栈中的当前子例程),这是调度中不常见的操作,尤其是在AUTOLOAD中:

     转到 ⊂
    
  7. 调用以 Perl 内置函数命名的子例程。 & 始终为您提供用户定义的值。这就是为什么我们在学习中教授它Perl。通常您并不想这样做,但它是 & 的功能之一。

在某些地方您可以使用它们,但还有更好的方法:

  1. 调用与 Perl 内置函数同名的子例程。只是不要有与 Perl 内置函数同名的子例程。检查 perlfunc 以查看不应使用的内置名称列表。

  2. 禁用原型。如果您不知道这意味着什么或为什么需要它,请不要使用 &。一些黑魔法代码可能需要它,但在这些情况下,您可能知道自己在做什么。

  3. 取消引用并执行子例程引用。只需使用 -> 符号即可。

I'm a frequent abuser of &, but mostly because I'm doing weird interface stuff. If you don't need one of these situations, don't use the &. Most of these are just to access a subroutine definition, not call a subroutine. It's all in perlsub.

  1. Taking a reference to a named subroutine. This is probably the only common situation for most Perlers:

     my $sub = \&foo;
    
  2. Similarly, assigning to a typeglob, which allows you to call the subroutine with a different name:

     *bar = \&foo;
    
  3. Checking that a subroutine is defined, as you might in test suites:

     if( defined &foo ) { ... }
    
  4. Removing a subroutine definition, which shouldn't be common:

     undef &foo;
    
  5. Providing a dispatcher subroutine whose only job is to choose the right subroutine to call. This is the only situation I use & to call a subroutine, and when I expect to call the dispatcher many, many times and need to squeeze a little performance out of the operation:

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
  6. To jump into another subroutine using the current argument stack (and replacing the current subroutine in the call stack), an unrare operation in dispatching, especially in AUTOLOAD:

     goto ⊂
    
  7. Call a subroutine that you've named after a Perl built-in. The & always gives you the user-defined one. That's why we teach it in Learning Perl. You don't really want to do that normally, but it's one of the features of &.

There are some places where you could use them, but there are better ways:

  1. To call a subroutine with the same name as a Perl built-in. Just don't have subroutines with the same name as a Perl built-in. Check perlfunc to see the list of built-in names you shouldn't use.

  2. To disable prototypes. If you don't know what that means or why you'd want it, don't use the &. Some black magic code might need it, but in those cases you probably know what you are doing.

  3. To dereference and execute a subroutine reference. Just use the -> notation.

不回头走下去 2024-08-10 16:53:34

IMO,唯一有理由使用 & 的情况是您正在获取或调用 coderef,例如:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

可以使用它的主要时间是<在大多数情况下,绝对不应该在调用具有指定任何非默认调用行为的原型的子程序时。我的意思是,某些原型允许重新解释参数列表,例如将 @array%hash 规范转换为引用。因此,子程序将期望发生这些重新解释,除非您尽一切努力来手动模仿它们,否则子程序将获得与它期望的输入截然不同的输入。

我认为主要是人们试图告诉你,你仍在使用 Perl 4 风格编写,而我们现在有一个更干净、更好的东西,称为 Perl 5。

关于性能,Perl 有多种方法来优化 & 失败的子调用,其中主要方法之一是常量内联。

还有一种情况,使用 & 可以提供性能优势:如果您使用 foo(@_) 转发子调用。使用 &foofoo(@_) 快得多。我不会推荐它,除非您通过分析明确发现您需要微优化。

IMO, the only time there's any reason to use & is if you're obtaining or calling a coderef, like:

sub foo() {
    print "hi\n";
}

my $x = \&foo;
&$x();

The main time that you can use it that you absolutely shouldn't in most circumstances is when calling a sub that has a prototype that specifies any non-default call behavior. What I mean by this is that some prototypes allow reinterpretation of the argument list, for example converting @array and %hash specifications to references. So the sub will be expecting those reinterpretations to have occurred, and unless you go to whatever lengths are necessary to mimic them by hand, the sub will get inputs wildly different from those it expects.

I think mainly people are trying to tell you that you're still writing in Perl 4 style, and we have a much cleaner, nicer thing called Perl 5 now.

Regarding performance, there are various ways that Perl optimizes sub calls which & defeats, with one of the main ones being inlining of constants.

There is also one circumstance where using & provides a performance benefit: if you're forwarding a sub call with foo(@_). Using &foo is infinitesimally faster than foo(@_). I wouldn't recommend it unless you've definitively found by profiling that you need that micro-optimization.

◇流星雨 2024-08-10 16:53:34

&subroutine() 形式禁用原型检查。这可能是也可能不是您想要的。

http://www.perl.com/doc/manual/html /pod/perlsub.html#Prototypes

原型允许您指定子例程参数的数量和类型,并在编译时检查它们。这可以提供有用的诊断帮助。

原型不适用于方法调用或使用 & 的老式风格进行的调用。前缀。

的&需要引用或取消引用子例程或代码引用

,例如

sub foo {
   # a subroutine
}

my $subref = \&foo; # take a reference to the subroutine

&$subref(@args);  # make a subroutine call using the reference.

my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this

原型也不适用于子例程引用。

&subroutine 形式也用于所谓的 magic goto 形式。

表达式 goto &subroutine 使用 @_ 的当前值,将当前调用上下文替换为对指定子例程的调用。

本质上,您可以将对一个子例程的调用完全切换为对指定子例程的调用。这在 AUTOLOAD 块中很常见,其中可以进行延迟的子例程调用,也许需要对 @_ 进行一些修改,但它看起来完全就像是对指定子程序的调用。

我想

sub AUTOLOAD {
    ...
    push @_, @extra_args; # add more arguments onto the parameter list
    goto &subroutine ; # change call another subroutine, as if we were never here
}

这对于尾调用消除可能很有用。

请参阅此处对此技术的详细说明

The &subroutine() form disables prototype checking. This may or may not be what you want.

http://www.perl.com/doc/manual/html/pod/perlsub.html#Prototypes

Prototypes allow you to specify the numbers and types of your subroutine arguments, and have them checked at compile time. This can provide useful diagnostic assistance.

Prototypes don't apply to method calls, or calls made in the old-fashioned style using the & prefix.

The & is necessary to reference or dereference a subroutine or code reference

e.g.

sub foo {
   # a subroutine
}

my $subref = \&foo; # take a reference to the subroutine

&$subref(@args);  # make a subroutine call using the reference.

my $anon_func = sub { ... }; # anonymous code reference
&$anon_func(); # called like this

Protypes aren't applicable to subroutine references either.

The &subroutine form is also used in the so-called magic goto form.

The expression goto &subroutine replaces the current calling context with a call to the named subroutine, using the current value of @_.

In essence, you can completely switch a call to one subroutine with a call to the named one. This is commonly seen in AUTOLOAD blocks, where a deferred subroutine call can be made, perhaps with some modification to @_ , but it looks to the program entirely as if it was a call to the named sub.

e.g.

sub AUTOLOAD {
    ...
    push @_, @extra_args; # add more arguments onto the parameter list
    goto &subroutine ; # change call another subroutine, as if we were never here
}

}

Potentially this could be useful for tail call elimination, I suppose.

see detailed explanation of this technique here

电影里的梦 2024-08-10 16:53:34

我读过反对使用“&”的论点,但我几乎总是使用它。它为我节省了太多时间。我花费了很大一部分 Perl 编码时间来查找代码的哪些部分调用了特定的函数。通过前导 &,我可以立即搜索并找到它们。如果没有前导 &,我会得到函数定义、注释和调试语句,通常是我必须检查才能找到我要查找的内容的代码量的三倍。

最主要的是不使用“&”购买你的是它可以让你使用函数原型。但是 Perl 函数原型可能会经常产生错误,就像它们阻止错误一样,因为它们会获取您的参数列表并以您可能意想不到的方式重新解释它,以便您的函数调用不再传递它字面上所说的参数。

I've read the arguments against using '&', but I nearly always use it. It saves me too much time not to. I spend a very large fraction of my Perl coding time looking for what parts of the code call a particular function. With a leading &, I can search and find them instantly. Without a leading &, I get the function definition, comments, and debug statements, usually tripling the amount of code I have to inspect to find what I'm looking for.

The main thing not using '&' buys you is it lets you use function prototypes. But Perl function prototypes may create errors as often as they prevent them, because they will take your argument list and reinterpret it in ways you might not expect, so that your function call no longer passes the arguments that it literally says it does.

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