2009-09-28 2 views
4

Следующий код выдает сообщение об ошибке:Есть ли способ изменить переменную цикла foreach?

#!/usr/bin/perl -w 

foreach my $var (0, 1, 2){ 
    $var += 2; 
    print "$var\n"; 
} 

Modification of a read-only value attempted at test.pl line 4.

Есть ли способ изменить $var? (Я просто спрашиваю из любопытства. Я был на самом деле очень удивлен видеть это сообщение об ошибке)

+0

Почему вы * хотите * изменить переменная цикла? Это звучит как способ сделать поведение цикла непредсказуемым. * Но возможно, это то, что вы хотите? * – pavium

+3

Это не делает поведение цикла непредсказуемым в том смысле, что оно не мешает итератору. Результат может быть неожиданным, но он вполне предсказуем. –

+0

+1 для любопытства и желания понять сообщения об ошибках, даже если вы уже нашли обходное решение :-). – sleske

ответ

12

В foreach $var (@list) конструкции, $var становится дискретным к элементам цикла, в том смысле, что адрес памяти $var будет тот же адрес, что и элемент @list. Таким образом, ваш примерный код пытается изменить значения только для чтения, и вы получите сообщение об ошибке.

Этот небольшой скрипт покажет, что происходит в foreach конструкции:

my @a = (0,1,2); 
print "Before: @a\n"; 
foreach my $var (@a) { 
    $var += 2; 
} 
print "After: @a\n"; 

Before: 0 1 2 
After: 2 3 4 

Дополнительная информация:This item от perlsyn легко замазать, но дает целый совок:

Контурные петли

...

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

5

Perl жалуется на значения, которые являются константами, а не переменной цикла. Значение readonly, на которое он жалуется, является вашим 0, потому что $var является псевдонимом для него, и он не сохраняется в переменной (что-то, что вы можете изменить). Если вы перебираете массив или список переменных, у вас нет этой проблемы.

4

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

#!/usr/bin/perl 

use strict; 
use warnings; 

for my $x (@{[ 0, 1, 2 ]}) { 
    $x += 2; 
    print $x, "\n"; 
} 
Смежные вопросы