嵌套循环中的Perl $ _变量工作机制

时间:2014-04-11 15:56:46

标签: perl

这是Perl代码的一部分,带有嵌套循环,plz忽略未定义的变量。我对这个$_工作机制感到困惑。在外面和循环中。

假设:@sfiles = A.c B.c C.c

执行后,数组@sfiles将被匹配$symbol的内循环覆盖。

我不确定$_是否像使用这些@sfile或打开文件的C指针一样使用?

foreach (@sfiles) {

  my $fpname = $sdir . '/' . $_;
  open SOURCEFILE, '<', $fpname or die "Failed to open file [$fpname].  $!";

  while (<SOURCEFILE>) {
    chomp;
    next if /\/\//;

    if (/\/\*/) {
      while (<SOURCEFILE>) {
        chomp;
        last if /\*\//;
      }
    }
    if (/$symbol/) {
      $reference = 'refered';
      last;
    }
  }

  close(SOURCEFILE);

  last if $reference;
}

2 个答案:

答案 0 :(得分:8)

我建议几乎所有情况都避免使用$_。假设你的代码更像英语,但它确实没有提高可读性:

for ( @array ) {
    next unless /^foo/;
    print;
}

这真的比这更具可读性吗?

for my $item ( @array ) {
    next unless $item =~ /^foo/;
    print "$item\n";
}

也不是,它有任何类型的魔法属性(如Borodin在他的答案中暗示的那样)另一个变量不会有。任何变量,而不仅仅是$_都会被for循环中的元素别名化。在此计划中,我只需更改变量three的值,即可将buzz更改为数组中的$item

use strict;
use warnings;

my @array = qw(one two three four five);

for my $item ( @array ) {
    if ( $item eq "three" ) {
        $item = "buzz";   # Will actually change $array[2]
    }
}

#
# Let's print out my array and see if $array[2] got changed.
#
for my $item ( @array ) {
    print "$item\n";
}

打印出来:

one
two
buzz
four
five

更糟糕的是,$_无论如何都会在长度超过几行的任何循环中引起它的丑陋。在您的示例中,您有:

my $fpname = $sdir . '/' . $_;

非常隐蔽。

在您的示例中,您注意到$_的值似乎在内循环和外循环中都保持有效。也就是说,即使我使用相同的变量,两个循环也不会相互干扰。

这是因为每个循环$_ 已本地化。它是Perl mishmash概念中非Perl开发人员咆哮和狂热的概念之一。

$_在两个循环中都是相同的变量。 $_的范围是全球性的。但是,在每个循环中,此全局变量包含的值已本地化到循环范围。咦?请参阅local并准备好让自己的思绪受到影响。某人通常需要几年时间才能了解包(也称为全局)范围变量词法(又称本地)范围变量之间的区别包括范围(又称全局)变量的本地化。难怪为什么所有Python程序员都取笑我。

正如ysth所述,虽然使用$_恰好可行,但如果在每个循环中使用实际变量,则您的程序将更容易理解。此外,想象如果你需要在while循环中来自该行的文件的名称会发生​​什么。 (warn文件$ _中的$ _行格式不正确&#34 ;;`)。

当循环中有循环时,您可能希望使用标签。标签可用于指出nextlast应该转到哪个循环:

FILE:
for my $source_file ( @files ) {
   open my $source_fh, "<", $source_file;   # Use autodie...
   LINE:
   while ( my $line = <$file> ) {
      ...
      ...
      next LINE if ...   # Don't need this line
      ...
      ...
      next FILE if ...  # I'm done with this file
      ...
   }
}

即使您没有像我一样使用next FILE,标签也会让您的程序更清晰一些。您不仅要进入循环的下一次迭代,而且还要转到文件的下一个 LINE

答案 1 :(得分:5)

是的,foreach将循环变量别名化为循环的元素。出于这个原因,你最好不要使用默认变量,而是做:

foreach my $file (@sfiles) {
    ...
    while ( my $line = <SOURCEFILE> ) {
       ...