0

次のコードは @populations のコンテンツを食べます

@populations=("EUR","AFR","ASN","AMR");
print @populations,"\n";  #will show EURAFRASNAMR
foreach (@populations)
{  
    $filepath="tmp.txt"; #whatever text file you like 
    open(FILE,"<$filepath");
    while(<FILE>)
    {   
    }   
}   
print @populations,"\n";   #will print nothing

に変更する場合

foreach $i (@populations)

配列は食べられません。

またはwhileループをマークすると、配列は食べられません。

私は perl の第一人者ではありませんが、数年の経験があります。

誰でも理由を教えてもらえますか?perlのバグですか?

4

2 に答える 2

6

正確にはバグではありませんが、不注意な人にとっては罠です。の要素を変数に暗黙的に代入@populationsし、ファイルハンドル$_から にデータを読み込み、 の内容を上書きします。FILE$_@populations

より明示的には、コードは次と同等です。

@populations=("EUR","AFR","ASN","AMR");
print @populations,"\n";  #will show EURAFRASNAMR
foreach $_ (@populations)    # $_ becomes "aliased" to the element in @populations
{  
    $filepath="tmp.txt"; #whatever text file you like 
    open(FILE,"<$filepath");
    while(defined($_ = <FILE>))  # overwrites $_, and erases element in @populations
    {   
    }   
}   
print @populations,"\n";   #will print nothing

ループ内$_で暗黙的に使用することを避けるための適切な回避策を見つけました。for

于 2013-02-15T21:58:18.363 に答える
5
while (<$fh>) { ... }

に置き換えられます

while (defined($_ = <$fh>)) { ... }

これが、読み取った値が で使用できる理由です$_。問題は、$_現在 の要素にエイリアスされていることです@populations

あなたが言ったように、使用することでその問題を回避できます

for my $population (@populations) {  
   ...
   while (<FILE>) { ... $_ ... }
   ...
}

しかし、それはまだ$_呼び出し元のサブから上書きすることができます. さらに 2 つの堅牢な修正を次に示します。

for (@populations) {  # Or: for my $population (@populations) {  
   ...
   while (my $line = <FILE>) { ... $line ... }
   ...
}   

また

for (@populations) {  # Or: for my $population (@populations) {  
   ...
   while (local $_ = <FILE>) { ... $_ ... }
   ...
}

まったく同じ理由で、ファイル ハンドルにグローバル変数を使用しないでください。

$filepath="tmp.txt"; #whatever text file you like 
open(FILE,"<$filepath");
<FILE>

する必要があります

my $filepath="tmp.txt";
open(my $FILE, "<", $filepath) or die $!;
<$fh>

ちなみにいつも使ってますuse strict; use warnings;

于 2013-02-15T22:02:02.670 に答える