Я использую each
для перебора Perl-хэша:
while (my ($key,$val) = each %hash) {
...
}
Затем происходит что-то интересное, и я хочу распечатать хэш. Сначала я думаю что-то вроде:
while (my ($key,$val) = each %hash) {
if (something_interesting_happens()) {
foreach my $k (keys %hash) { print "$k => $hash{$k}\n" }
}
}
Но это не сработает, потому что все знают, что вызов keys
(или values
) на хеше сбрасывает внутренний итератор, используемый для each
, и мы можем получить бесконечный цикл. Например, эти скрипты будут работать вечно:
perl -e '%a=(foo=>1); while(each %a){keys %a}'
perl -e '%a=(foo=>1); while(each %a){values %a}'
Нет проблем, подумал я. Я мог бы сделать копию хеша и распечатать копию.
if (something_interesting_happens()) {
%hash2 = %hash;
foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" }
}
Но и это не работает. Это также сбрасывает итератор each
. На самом деле, любое использование %hash
в контексте списка приводит к сбросу его each
итератора. Так что они тоже работают вечно:
perl -e '%a=(foo=>1); while(each %a){%b = %a}'
perl -e '%a=(foo=>1); while(each %a){@b = %a}'
perl -e '%a=(foo=>1); while(each %a){print %a}'
Это где-нибудь задокументировано? Вполне логично, что perl может потребоваться использовать тот же внутренний итератор для помещения содержимого хэша в стек возврата, но я также могу представить реализации хеширования, в которых этого делать не нужно.
Что еще более важно, есть ли способ сделать то, что я хочу? Чтобы добраться до всех элементов хеша без сброса итератора each
?
Это также говорит о том, что вы не можете отлаживать хэш внутри каждой
итерации.Рассмотрите возможность запуска отладчика на:
%a = (foo => 123, bar => 456);
while ( ($k,$v) = each %a ) {
$DB::single = 1;
$o .= "$k,$v;";
}
print $o;
Просто проверив хэш, где отладчик останавливается (скажем, набрав p %a
или x %a
), вы измените вывод программа.
Обновление:Я загрузилHash::SafeKeys
в качестве общего решения этой проблемы. Спасибо @gpojd за то, что указал мне правильное направление, и @cjm за предложение, которое значительно упростило решение.