我何时应该使用&调用Perl子例程?

use*_*033 48 perl subroutine

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

function($a,$b,...);
# opposed to
&function($a,$b,...);
Run Code Online (Sandbox Code Playgroud)

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

当省略时,性能增加如何发挥作用&呢?

bri*_*foy 52

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

  1. 引用一个命名子例程.这可能是大多数Perlers的唯一常见情况:

     my $sub = \&foo;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 同样,分配给typeglob,它允许您使用不同的名称调用子例程:

     *bar = \&foo;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 检查是否定义了子例程,就像在测试套件中一样:

     if( defined &foo ) { ... }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 删除子例程定义,这不应该是常见的:

     undef &foo;
    
    Run Code Online (Sandbox Code Playgroud)
  5. 提供一个调度程序子程序,其唯一的工作是选择要调用的正确子程序.这是我唯一使用的情况&调用一个子程序,当我想到打电话给调度员无数次,需要挤一点表现出来的操作:

     sub figure_it_out_for_me {
        # all of these re-use the current @_
          if( ...some condition... ) { &foo     } 
       elsif( ...some other...     ) { &bar     }
       else                          { &default }
       }
    
    Run Code Online (Sandbox Code Playgroud)
  6. 跳进其他子程序使用当前参数堆栈(和更换在调用栈中的当前子程序),在分派unrare操作,特别是在AUTOLOAD:

     goto ⊂
    
    Run Code Online (Sandbox Code Playgroud)
  7. 调用您在Perl内置后命名的子例程.将&始终为您提供了用户定义的.这就是我们在Learning Perl中教它原因.你真的不想这样做,但它是其中一个特点&.

有些地方你可以使用它们,但有更好的方法:

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

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

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

  • 此外,` - > can`遵循继承.不告诉您子例程是否实际位于当前包中. (6认同)
  • `can`不告诉你是否定义了子程序.它告诉你一个名为`can`的子程序是否希望你认为它被定义,即使它不是. (2认同)

cha*_*aos 36

IMO,唯一有理由使用的&是你获得或调用coderef,如:

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

my $x = \&foo;
&$x();
Run Code Online (Sandbox Code Playgroud)

主要的时间,你可以,你使用它绝对不应该在大多数情况下,调用一个已具雏形,指定任何非默认调用行为子时.我的意思是,一些原型允许重新解释参数列表,例如转换@array%hash规范参考.因此,sub会期望这些重新解释已经发生,并且除非你达到手动模仿它们所需的任何长度,否则sub将获得与它预期的输入大不相同的输入.

我认为主要是人们试图告诉你,你仍然用Perl 4风格写作,现在我们有一个更干净,更好的东西叫做Perl 5.

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

还有一种情况是使用&提供了性能优势:如果您正在转发子呼叫foo(@_).使用&foo比无限快foo(@_).除非你通过剖析确定你需要微观优化,否则我不会推荐它.

  • 除此之外,`&$ x()`并不是调用代码ref的最佳方式; 你应该只是取消引用它,就像任何其他ref:$ x - >(). (24认同)
  • 我在呼叫中使用`&`的唯一时间是`AUTOLOAD`.目的不是优化,但是,如果有人想要进行回溯,那就是清理调用堆栈. (3认同)
  • &禁用原型检查的另一个必然结果:如果你有一个函数原型来将coderef作为它的第一个参数(la`map()`/`grep()`),并且你想要在标量中传递该函数的coderef变量,那么你必须在调用中使用&.如果不这样做,Perl会抱怨,因为它希望函数的名称或括号内置函数作为第一个参数. (2认同)
  • Robert...coderef-deref 是我在 Perl 5.004 中添加的(在 Chip Salzenberg 的帮助下)。一些遗留文档是在此之前编写的。 (2认同)

cms*_*cms 18

&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
Run Code Online (Sandbox Code Playgroud)

原型也不适用于子程序引用.

&subroutine表单也用于所谓的magic goto表单.

该表达式goto &subroutine使用@_的当前值替换当前调用上下文,并调用named子例程.

实质上,您可以通过调用指定的子程序将调用完全切换到一个子例程.这在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
}
Run Code Online (Sandbox Code Playgroud)

}

我想这可能对尾部呼叫消除有用.

在这里看到这种技术的详细解释