【问题标题】:How is $_ different from named input or loop arguments?$_ 与命名输入或循环参数有何不同?
【发布时间】:2011-03-23 12:44:33
【问题描述】:

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

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

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

所以如果我使用

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 之后,我得出了一个结论:

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

感谢您对此事的澄清。

【问题讨论】:

  • 甚至print for @array ;)
  • 解决您的更新:$_ 仍然是一个全局变量,但在每个循环中隐式本地化。例如,请参阅stackoverflow.com/questions/2238576。
  • $ man perlsyn,寻找 Foreach 循环。
  • @mob:在每个 for/foreach 循环中隐式本地化。 不在while (<>)循环内隐式本地化

标签: perl perlvar


【解决方案1】:
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。所有其他地方都要求您自己进行本地化(),因此当您不可避免地忘记这样做时,您将注入潜在的错误。 :-)

【讨论】:

  • 是的,提出正确的问题有时是最困难的部分;)
【解决方案2】:

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

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

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

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

【讨论】:

  • 当你在这样的子程序中使用$_ 时,你也应该在其中有一个local ($_,$.);。
【解决方案3】:

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

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

【讨论】:

  • 它似乎与命名变量不一样,因为 perlvar 提到了副作用,因为它是全局的。关于可读性,我同意嵌套循环。
  • 没错,我应该更清楚,尤其是你提到了全局方面。如果您稍后尝试使用它,它可能已经被初始化或您没有预料到的东西,或者您可能已经覆盖了您期望的值。我为此道歉。当我确实使用 $_ 时,它只是在一个非常小的循环或映射的上下文中,所以我忘记了。
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • Lexical $_ 需要 Perl v5.10 或更高版本。
    猜你喜欢
    • 2023-01-05
    • 2017-07-24
    • 2021-03-17
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多