$ _与命名输入或循环参数有何不同?

时间:2011-03-23 12:44:33

标签: perl perlvar

因为我使用$ _很多,我想更好地理解它的用法。就我所理解和使用而言,$ _是隐含值的全局变量。

由于$ _似乎已设置,是否有理由使用命名循环变量而不是可读性?

在什么情况下,重要的是_ _是一个全局变量?

所以,如果我使用

for (@array){
    print $_;
}

甚至

print $_ for @array;

它与

具有相同的效果
for my $var (@array){
    print $var;
}

但它的功能是否相同?我想这不完全是但实际差异是什么?

更新

在这个例子中,似乎$ _甚至是正确的范围。它不再是全球性的吗?我使用的是5.12.3。

#!/usr/bin/perl
use strict;
use warnings;

my @array = qw/one two three four/;
my @other_array = qw/1 2 3 4/;

for (@array){
    for (@other_array){
        print $_;
    }
    print $_;
}

正确打印1234one1234two1234three1234four。

对于全球$ _我预计1234 4 1234 4 1234 4 1234 4 ..或我错过了一些明显的东西吗?

什么时候是$ _ global呢?

更新

好的,在仔细阅读了各种答案和perlsyn后,我得出了一个结论:

除了可读性之外,最好避免使用$ _,因为必须知道$ _的隐式本地化并考虑到否则可能会遇到意外行为。

感谢您澄清此事。

5 个答案:

答案 0 :(得分:8)

使用$_(隐式或显式)作为循环变量的经典失败模式是

for $_ (@myarray) {
  /(\d+)/ or die;
  foo($1);
}

sub foo {
  open(F, "foo_$_[0]") or die;
  while (<F>) {
    ...
  }
}

其中,因为for / foreach中的循环变量绑定到实际列表项,意味着while (<F>)用文件中读取的行覆盖@myarray

答案 1 :(得分:8)

are there reasons to use named loop variables over $_ besides readability?

问题不在于它们是否被命名。问题是它们是“包变量”还是“词汇变量”。

请参阅Perl“应对范围”中使用的2个变量系统的非常好的描述:

http://perl.plover.com/FAQs/Namespaces.html

包变量是全局变量,因此应该避免出于所有常见原因(例如远距离行动)。

避免包变量是“正确操作”或“更难注入错误”的问题,而不是“可读性”的问题。

In what cases does it matter $_ is a global variable?

无处不在。

更好的问题是:

In what cases is $_ local()ized for me?

有些地方Perl会为你本地()ize $ _,主要是foreach,grep和map。所有其他地方都要求你自己本地()使用它,因此当你不可避免地忘记这样做时,你会注入一个潜在的错误。 : - )

答案 2 :(得分:3)

$ _与在第二个示例中使用通常使用的方式命名变量相同。 $ _只是当前循环中当前项的快捷默认变量名,以便在执行快速,简单的循环时节省输入。我倾向于使用命名变量而不是默认值。它使它更清楚它是什么,如果我碰巧需要做一个嵌套循环,没有冲突。

由于$ _是一个全局变量,如果您尝试使用它来自前一个代码块的值,则可能会得到意外的值。新的代码块可能是循环或其他操作的一部分,它将自己的值插入$ _,覆盖了您期望的那些。

答案 3 :(得分:2)

使用$ _的风险在于它是全局的(除非你使用local $_进行本地化),因此如果你在循环中调用的某些函数也使用$ _,那么这两种用法都会产生干扰。

由于我不清楚的原因,这偶尔只会咬我,但如果我在包内使用它,我通常会本地化$ _。

答案 4 :(得分:1)

$_除了它是许多函数的默认参数之外没有什么特别之处。如果您使用$_明确地将my范围用于词法范围,则perl将使用$_的本地版本而不是全局版本。这没有什么奇怪的,它就像任何其他命名变量一样。

sub p { print "[$_]"; } # Prints the global $_
# Compare and contrast
for my $_ (b1..b5) { for my $_ (a1..a5) { p } } print "\n"; # ex1
for my $_ (b1..b5) { for       (a1..a5) { p } } print "\n"; # ex2
for       (b1..b5) { for my $_ (a1..a5) { p } } print "\n"; # ex3
for       (b1..b5) { for       (a1..a5) { p } } print "\n"; # ex4

你应该对输出略微神秘,直到你发现perl将在循环退出时保留循环变量的原始值(参见 perlsyn )。

注意上面的 ex2 。这里第二个循环使用在第一个循环中声明的词法范围$_。微妙但预期。同样,这个值在退出时保留,因此两个循环不会干扰。