这是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;
}
答案 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 ;;`)。
当循环中有循环时,您可能希望使用标签。标签可用于指出next
或last
应该转到哪个循环:
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> ) {
...