2008-12-03 2 views
4

Perl, кажется, убивает мой массив каждый раз, когда я прочитал файл:Почему вызов этой функции меняет мой массив?

my @files = ("foo", "bar", "baz"); 
print "Files: " . join(" ", @files) . "\n"; 

foreach(@files) { 
    print "The file is $_\n"; 
    func(); 
} 

sub func { 
    open(READ, "< test.txt"); 
    while(<READ>) { 
    } 
    close READ; 
} 

print "Files: " . join(" ", @files) . "\n"; 

производит:

Files: foo bar baz 
The file is foo 
The file is bar 
The file is baz 
Files: 

, но когда я закомментировать func(), это дает то, что я бы ожидать:

Files: foo bar baz 
The file is foo 
The file is bar 
The file is baz 
Files: foo bar baz 

Любые идеи, почему это может произойти?

ответ

12

Вы должны изменить foo, чтобы локализовать $_, или не использовать $_ в вашей петле. Еще лучше, сделайте так:

foreach my $filename (@files) { 
    print "The file is $filename\n"; 
    func(); 
} 

sub func { 
    local $_; 
    open my $read, '<', 'test.txt' or die "Couldn't open test.txt: $!"; 
    while(<$read>) { 
    } 
    close $read or die "Couldn't close file: $!"; 
} 

в цикле, псевдонимами цикл $_ к текущему имени файла и while(<READ>) присвоит к $_. Это плохое сочетание магии, так сказать.

В общем, неплохо полагаться на то, что на $_ на что-то другое, кроме однострочного.

+0

my $ _; (Только 5.10+) - лучший способ сделать это – ysth 2008-12-03 04:37:00

+0

Правда, но дистрибутивы только начинают двигаться до 5.10. Я полагаю, что люди по-прежнему на 5.8 по большей части. – 2008-12-03 13:47:20

3

Это должен был быть комментарий к ответу Леона, но у меня пока нет репутации; мои извинения.

Незначительная ошибка: $ filename должно было заменить $ _ в теле цикла foreach.

Незначительный nitpick: я бы посоветовал всегда использовать три формы аргумента open, используя лексический дескриптор файла, даже в коротких примерах.

foreach my $filename (@files) { 
    print "The file is $filename\n"; 
    func(); 
} 

sub func { 
    open my $read, '<', 'test.txt' or die $!; 
    while(<$read>) { 
    } 
    close $read or die $!; 
} 

print 'Files: ' . join(' ', @files) . "\n"; 
Смежные вопросы