Perl里有个奇怪的标量变量叫做$_,它是默认变量,换句话说是主题。

Perl里好多函数或者操作符默认使用这个变量,以防没有明确提供参数。 总的来说,我认为你应该在实际代码里看到$_。 我认为$_的意思在于你不需要明确写出来。

当然,除非你写了。

拥有一个默认变量是个很强大的想法,但是不正确地使用它会降低你的代码的可读性。 看下这个脚本:

use strict;
use warnings;
use v5.10;

while (<STDIN>) {
   chomp;
   if (/MATCH/) {
      say;
   }
}

这跟下边这个几乎一样:

use strict;
use warnings;
use v5.10;

while ($_ = <STDIN>) {
   chomp $_;
   if ($_ =~ /MATCH/) {
      say $_;
   }
}

我从不写第二种,第一种也只是写在很小的脚本里或者代码里紧致的部分。甚至都不写。

如你所见,在while循环里,当你从文件句柄甚至是从标准输入读入时,如果不显式赋值给一个变量,读取的这一行会被赋值给$_

如果没有提供参数,chomp()默认操作于该变量。

正则表达式匹配可以不显式提供字符串,甚至不写=~操作符。如果这么写时,它将会对$_的内容进行操作。

最后say()类似于print()会打印$_的内容,如果不提供其他参数的话。

split

split的第二个参数是要被分割的字符串。如果没有提供第二个参数,split将分割$_的内容。

my @fields = split /:/;

foreach

如果我们不给foreach提供迭代变量的名称,它会使用$_

use strict;
use warnings;
use v5.10;

my @names = qw(Foo Bar Baz);
foreach (@names) {   # puts values in $_
    say;
}

条件赋值

有些情况下,我们可能由于隐含使用了$_导致错误。

一些高手可能有意写这种代码,但是新手或者初学者这么写的话,这就是bug了。

if ($line = /regex/) {
}

你可以发现,我们使用了普通的赋值操作符:=而非正则表达式操作符:=~。 这实际上跟下边这个一样

if ($line = $_ =~ /regex/) {
}

它获取$_的内容,并对之进行模式匹配,接着把结果赋值给$line。然后检查$line的内容是真或假。

显式$_

我前边说过,建议不要显式使用$_。 有时我看到人们这么写代码:

while (<$fh>) {
  chomp;
  my $prefix = substr $_, 0, 7;
}

我认为,如果你使用perl的某个声明需要强制显式地写出$_,比如这个例子里的substr,你应该总是使用一个更有意义的名字。 即便它意味着更多键盘敲击:

while (my $line = <$fh>) {
  chomp $line;
  my $prefix = substr $line, 0, 7;
}

我经常看到另一种不好的例子:

while (<$fh>) {
   my $line = $_;
   ...
}

这很可能出现在人们不了解while语句,文件句柄读操作以及$_之间的交互时。

这可以以更简单的方式直接赋值给$line变量。

while (my $line = <$fh>) {
   ...
}

例外

有些情况下,你不可避免地需要显式使用$_。 此类有grepmap函数以及其他类似any的函数。