【问题标题】:Perl using the special character &Perl 使用特殊字符 &
【发布时间】:2013-06-18 16:06:59
【问题描述】:

我有一个小问题。我正在阅读一些代码,因为我的学校没有教我任何有关 perl 编程的有用知识,所以我在这里问你们。我看到这一行在一些 perl 程序中被大量使用:

$variable = &something();

我不知道 & 符号在这里是什么意思,因为我从来没有在 perl 中说过。 something 是一个子程序(我猜)。它通常说一个名字,有时它也有像函数一样的参数。谁能告诉我& 在这里代表什么以及something 一直是什么。

变量接受某种返回值,然后用于检查某些条件,这让我觉得它是一个子程序。但是为什么还要&?

谢谢

【问题讨论】:

    标签: perl


    【解决方案1】:

    几乎每次您在\&foo 和EXRP && EXPR 之外看到&,都是错误的。


    • &foo(...) 与 foo(...) 相同,但 foo 的原型将被忽略。

      sub foo(&@) { ... }      # Cause foo to takes a BLOCK as its first arg
      
      foo { ... } ...;
      &foo(sub { ... }, ...);  # Same thing.
      

      &foo(...) 只会调用子例程(而不是运算符)。

      sub print { ... }
      print(...);         # Calls the print builtin
      &print(...);        # Calls the print sub.
      

      您可能永远不需要在整个编程生涯中使用此功能。如果您看到它被使用,那肯定是有人在不应该使用 & 时使用。

    • &foo 类似于 &foo(@_)。不同的是,foo 中对@_ 的更改会影响当前子的@_。

      您可能永远不需要在整个编程生涯中使用此功能。如果您看到它被使用,那肯定是有人在不应该使用& 时使用它,或者是愚蠢的优化尝试。但是,以下内容非常优雅:

      sub log_info  { unshift @_, 'info';  &log }
      sub log_warn  { unshift @_, 'warn';  &log }
      sub log_error { unshift @_, 'error'; &log }
      
    • goto &foo 与&foo 类似,不同之处在于首先从调用堆栈中删除当前子例程。例如,这将导致它不会出现在堆栈跟踪中。

      您可能永远不需要在整个编程生涯中使用此功能。如果你看到它被使用,那肯定是一种愚蠢的优化尝试。

      sub log_info  { unshift @_, 'info';  goto &log; } # These are slower than
      sub log_warn  { unshift @_, 'warn';  goto &log; } # not using goto, but maybe
      sub log_error { unshift @_, 'error'; goto &log; } # maybe log uses caller()?
      
    • $& 包含最后匹配的正则表达式匹配。在 5.20 之前,使用它会导致整个解释器中的每个正则表达式变慢(如果它们没有捕获),所以不要使用它。

      print $&        if /fo+/;     # Bad before 5.20
      print $MATCH    if /fo+/;     # Bad (Same thing. Requires "use English;")
      print ${^MATCH} if /fo+/p;    # Ok (Requires Perl 5.10)
      print $1        if /(fo+)/;   # Ok
      
    • defined &foo 是检查子例程是否存在的一种完全合法的方法,但您可能永远不需要它。还有exists &foo类似,但没那么好用。

    • EXPR & EXPR 是按位与运算符。这用于处理在一个单词中存储多条信息的低级系统。

      system($cmd);
      die "Can't execute command: $!\n"       if $? == -1;
      die "Child kill by ".($? & 0x7F)."\n"   if $? & 0x7F;
      die "Child exited with ".($? >> 8)."\n" if $? >> 8;
      
    • &{ EXPR }()(和&$ref())是通过引用进行的子例程调用。尽管我更喜欢$ref->() 语法,但这是完全可以接受且有些常见的事情。下一项中的示例。

    • \&foo 引用子程序foo。这是一个完全可以接受且有些常见的事情。

      my %dispatch = (
         foo => \&foo,
         bar => \&bar,
      );
      
      my $handler = $dispatch{$cmd} or die;
      $handler->();
      # Same:  &{ $handler }();
      # Same:  &$handler();
      
    • EXPR && EXPR 是布尔 AND 运算符。我相信你对这个极其常见的运算符很熟悉。

      if (0 <= $x && $x <= 100) { ... }
      

    【讨论】:

    • 这应该是 &amp; 用于取消引用的用法? perl -E '&amp;{sub{ say pop }}( 4 )'
    • @mpapec,是的,虽然我更喜欢sub { say pop }-&gt;( 4 )。已添加。
    • 注意:子语言(例如原型、正则表达式模式)也可以使用&amp;。
    【解决方案2】:

    在旧版本的 perl 中,&amp; 用于调用子程序。现在这不是必需的,\&amp; 主要用于将reference 带入子程序,

    my $sub_ref = \&subroutine;
    

    或忽略函数原型 (http://perldoc.perl.org/perlsub.html#Prototypes)

    除了引用子程序&amp;是bitwise and操作符,

    http://perldoc.perl.org/perlop.html#Bitwise-And

    【讨论】:

    • 哦,所以如果我将其更改为不带 & 符号,它仍然可以工作吗?
    • 好的。所以我无法找到它指向的功能。它必须在其他文件中。但是你能告诉我他们是如何在不使用包的情况下从另一个文件调用函数的吗:package::sub()
    • 我需要自己制作一个......所以我需要一些理解
    • 您的脚本看起来如何?您可以引用包方法并通过引用调用它,my $f = \&amp;package::sub; $f-&gt;();
    • @ikegami - 来自 .pl 扩展名和代码中的 '&foo()',我希望它是非常旧的代码,而不是使用包,而是做这样的事情:文件.pl sub foo { ... } 1; 然后require file.pl; foo()
    猜你喜欢
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    相关资源
    最近更新 更多