3

当我经常使用 $_ 时,我想更好地了解它的用法。据我了解和使用,$_ 是隐式值的全局变量。

由于 $_ 似乎无论如何都设置了,除了可读性之外,还有理由在 $_ 上使用命名循环变量吗?

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

所以如果我使用

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 .. 还是我错过了一些明显的东西?

那么 $_ 什么时候是全局的呢?

更新

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

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

感谢您澄清此事。

4

5 回答 5

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

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

请参阅 Perl “Coping with Scoping”中使用的 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 会在一些地方为您本地化()$_,主要是 foreach、grep 和 map。所有其他地方都要求您自己进行本地化(),因此当您不可避免地忘记这样做时,您将注入潜在的错误。:-)

于 2011-03-23T14:13:17.493 回答
8

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

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

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

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

于 2011-03-23T12:52:32.643 回答
3

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

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

于 2011-03-23T12:47:13.690 回答
2

使用 $_ 的风险在于它是全局的(除非您使用 本地化它local $_),因此如果您在循环中调用的某些函数也使用了 $_,那么这两种用法可能会相互干扰。

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

于 2011-03-23T12:51:12.877 回答
1

$_除了它是许多函数的默认参数之外,没有什么特别之处。如果你明确地对你的$_with 进行词法范围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。这里第二个循环使用$_第一个循环中声明的词法范围。微妙,但在意料之中。同样,此值在退出时保留,因此两个循环不会干扰。

于 2011-03-23T13:21:15.937 回答