foreach и замена Perl переменной цикличного выполнения

Я пишу сценарий в Perl и имею вопрос о Perl foreach создать.

Кажется, что при изменении одной из переменных цикла, она изменяется в фактическом массиве. Этот на самом деле имеет место, или я сделал что-то полностью неправильно?

Я хочу поменять струну как abc.abc#a кому: abc_abc_a (символы нижнего подчеркивания для не алфавитно-цифровые символы), но я должен сохранить исходное значение в массиве для более позднего использования.

У меня есть код, который выглядит примерно так:

@strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
    $str =~ s/[^0-9A-Za-z]/_/g;
    print $str, "\n"; #Actually I use the string to manipulate files.
}

Я мог решить проблему путем выполнения следующего:

@strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
    my $temp = $str; #copy to a temporary value
    $temp =~ s/[^0-9A-Za-z]/_/g;
    print $temp, "\n"; #$str remains untouched...
}

но есть ли более эффективный способ выполнить это?

Большое спасибо!

15
задан KLee1 9 July 2010 в 23:53
поделиться

3 ответа

Вы не сумасшедшие; это нормальное поведение. См. perldoc perlsyn в разделе «Циклы по каждому элементу»:

Если какой-либо элемент LIST является lvalue, вы можете изменить его, изменив VAR внутри петля.И наоборот, если какой-либо элемент LIST НЕ является lvalue, любая попытка изменить это элемент выйдет из строя. Другими словами, индексная переменная цикла foreach является неявной псевдоним для каждого элемента в списке, который вы перебираете.

Другие итераторы цикла, такие как map , имеют аналогичное поведение:

 map BLOCK LIST
карта EXPR, СПИСОК

...
Обратите внимание, что $ _ является псевдонимом значения списка, поэтому его можно использовать для изменения элементы СПИСКА. Хотя это полезно и поддерживается, оно может вызвать странные результаты, если элементы LIST не переменные. Использование для этой цели обычного цикла foreach было бы яснее в большинстве случаев. См. Также "grep" для массива, состоящего из этих элементов. исходного списка, для которого BLOCK или EXPR оцениваются как истинные.

Вы могли бы переписать свой код таким образом, что, по крайней мере, избавило бы вас от добавления лишней строки:

my @strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (@strings){
    (my $copy = $str) =~ s/[^0-9A-Za-z]/_/g;
    print $copy, "\n";
}
16
ответ дан 1 December 2019 в 03:24
поделиться

Вы правы. Как указано в Программирование на Perl , переменная цикла является псевдонимом для текущего элемента массива, и вы должны сохранить переменную цикла, если какие-либо изменения не повлияют на исходное значение.

2
ответ дан 1 December 2019 в 03:24
поделиться

Вы всегда можете сделать копию массива перед изменением элементов в нем (' my »добавлено для успокоения strict ), а именно:

my @strings = ('abc.abc#a', 'def.g.h#i');
foreach my $str (my @temp = @strings) {
    $str =~ s/[^0-9A-Za-z]/_/g;
    print "$str\n"; #Actually I use the string to manipulate files.
}
use Data::Dumper;
print Dumper(\@strings);

, который возвращает:

abc_abc_a
def_g_h_i
$VAR1 = [
          'abc.abc#a',
          'def.g.h#i'
        ];

@temp не имеет области видимости вне цикла foreach .

3
ответ дан 1 December 2019 в 03:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: